I've been banging my head against this for a while. I am trying to make a game with PyGame and I got up to the collision segment and have been stuck for a while and have checked a few threads.
This is the code I have (removed other methods and conditional statements in between, but left the relevant parts). I am a little confused by the error because I do a self.imageRect = self.image.get_rect() in both classes init, yet I have this error. The error was specifically:
"AttributeError: 'Pebble' object has no attribute 'rect'" when the program attempts to carry out the collision detection part in the dog class. What have I been doing wrong?
import random
import pygame, sys
pygame.init()
clock = pygame.time.Clock() # fps clock
screenSize = WIDTH, HEIGHT = [800, 600]
screen = pygame.display.set_mode(screenSize)
background = pygame.Surface(screen.get_size())
bgColorRGB = [153, 204, 255]
background.fill(bgColorRGB)
pebbleGroup = pygame.sprite.Group()
pebbleSingle = pygame.sprite.GroupSingle()
dogSingle = pygame.sprite.GroupSingle()
#----------------------------------------------------------------------
class Dog(pygame.sprite.Sprite):
def __init__(self, path, speed):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(path) # load sprite from path/file loc.
self.imageRect = self.image.get_rect() # get bounds of image
self.imageWidth = self.image.get_width()
self.imageHeight = self.image.get_height()
self.speed = speed
# sets location of the image, gets the start location of object
# sets the start location as the image's left and top location
def setLocation(self, location):
self.imageRect.left, self.imageRect.top = location
def checkCollision(self, pebble, dogGroup):
if pygame.sprite.spritecollide(pebble, dogGroup, False):
print "collided"
#---------------------------------------------------------------------
class Pebble(pygame.sprite.Sprite):
def __init__(self, path, speed, location):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(path)
self.imageRect = self.image.get_rect()
self.imageWidth = self.image.get_width()
self.imageHeight = self.image.get_height()
self.imageRect.left, self.imageRect.top = location
self.speed = speed # initialize speed
self.isDragged = False
#----------------------------------------------------------------------
def startGame():
pebblePaths = ['images/pebble/pebble1.jpg', 'images/pebble/pebble2.jpg']
for i in range(3):
pebblePath = pebblePaths[random.randrange(0, len(pebblePaths))]
pebbleSpeed = [random.randrange(1, 7), 0]
pebbleLocation = [0, random.randrange(20, HEIGHT - 75)]
pebble = Pebble(pebblePath, pebbleSpeed, pebbleLocation)
pebbleGroup.add(pebble)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for pebble in pebbleGroup:
dog.checkCollision(pebble, dogSingle)
pygame.display.flip()
clock.tick(30) # wait a little before starting again
startGame()
It's expecting Sprite.rect, so change from
self.imageRect = self.image.get_rect()
#to
self.rect = self.image.get_rect()
Note
self.imageWidth = self.image.get_width()
self.imageHeight = self.image.get_height()
self.imageRect.left, self.imageRect.top = location
These are not necessary, since rect's have many properties, like self.rect.width or self.rect.topleft = location . Another useful one is centerx.
full list at: pygame Rect docs
Related
Im making a custom tile system for my game. Its my first time and didnt expect to go that far without a tutorial. So i did my best and made something that works when i render in a tile with the blit method but when i use pygame.sprite.Sprite sprites it doesnt work. I need it to be with pygame's sprite system because it makes it easier doing other stuff and im positive its a rookie mistake i just cant find it.
Code:
# Importing libraries
try:
import pygame
from pygame.locals import *
from time import *
from os import *
from random import *
import sys
print("All Libraries imported successfully \n")
except :
print("Error while importing modules and libraries")
sys.exit()
# Creating Screen
screen_width = 640
screen_height = 640
tile_size = int(screen_width / 10)
screen_res = (screen_width, screen_height)
clock = pygame.time.Clock()
running_fps = 144
screen = pygame.display.set_mode(screen_res)
pygame.display.set_caption(f"GTA Circuit Hack FPS:{running_fps}, {screen_width} x {screen_height}, Tile Size: {tile_size}")
# Loading images
# Background image:
backgroundImg = pygame.image.load("Background.png")
backgroundImg = pygame.transform.scale(backgroundImg, screen_res)
# Not walkable tile image:
noWalkTileImg = pygame.image.load("unwalkTile.png")
noWalkTileImg = pygame.transform.scale(noWalkTileImg, (tile_size, tile_size))
# making tiles
tiles = []
tile_y = 0
tile_x = 0
for i in range(10):
if i > 0:
tile_y += tile_size
for i in range(10):
if i > 0:
tile_x += tile_size
tiles.append((tile_x, tile_y))
tile_x = 0
tile_x = 0
tile_y = 0
# creating object classes
class BadTile (pygame.sprite.Sprite):
def __init__(self, tile):
pygame.sprite.Sprite.__init__(self)
self.image = noWalkTileImg
self.tile = tile
self.rect = self.image.get_rect()
self.x = self.tile[0]
self.y = self.tile[1]
def update(self):
self.x = self.tile[0]
self.y = self.tile[1]
# creating objects
tile1 = BadTile(tiles[99])
game_tiles = pygame.sprite.Group()
game_tiles.add(tile1)
run = True
while run:
clock.tick(running_fps)
screen.blit(backgroundImg, (0,0))
# rendering
game_tiles.update()
game_tiles.draw(screen)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.update()
pygame.quit()
print ("Exited with no errors")
sys.exit()
Images:
pygame.sprite.Group.draw() and pygame.sprite.Group.update() are methods which are provided by pygame.sprite.Group.
The latter delegates to the update method of the contained pygame.sprite.Sprites — you have to implement the method. See pygame.sprite.Group.update():
Calls the update() method on all Sprites in the Group. [...]
The former uses the image and rect attributes of the contained pygame.sprite.Sprites to draw the objects — you have to ensure that the pygame.sprite.Sprites have the required attributes. See pygame.sprite.Group.draw():
Draws the contained Sprites to the Surface argument. This uses the Sprite.image attribute for the source surface, and Sprite.rect. [...]
So you need to set self.rect.x and self.rect.y. Instead of self.x and self.y. You don't need self.x and self.y at all:
class BadTile (pygame.sprite.Sprite):
def __init__(self, tile):
pygame.sprite.Sprite.__init__(self)
self.image = noWalkTileImg
self.tile = tile
self.rect = self.image.get_rect()
self.rect.x = self.tile[0]
self.rect.y = self.tile[1]
def update(self):
self.rect.x = self.tile[0]
self.rect.y = self.tile[1]
I have tried everything I can think of to fix this, but I can't seem to find it. I know it is probably a simple fix, but I cannot find what is making this happen. This is the first part of my code :
import pygame, sys, time
from pygame.locals import *
pygame.init()
WINDOWWIDTH = 900
WINDOWHEIGHT = 400
MOVERATE = 5
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
TEXTCOLOR = (255, 255, 255)
BACKGROUNDCOLOR = (0, 0, 0)
FPS = 40
clock = pygame.time.Clock()
x = 200
y = 150
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
super(player, self).__init__()
temp_image = pygame.image.load("stand_down.png").convert_alpha()
self.image_down = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standleft.png").convert_alpha()
self.image_left = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standright.png").convert_alpha()
self.image_right = pygame.transform.scale(temp_image, (100, 200))
self.image = self.image_down
# keep position and size in pygame.Rect()
# to use it in collision checking
self.rect = self.image.get_rect(x=x, y=y)
def draw(self, x, y):
screen.blit(self.image, self.rect)
def handle_event(self):#, event)
self.image = self.image_down.get_rect()
self.image = pygame.Surface((x, y))
key = pygame.key.get_pressed()
if key[K_LEFT]:
self.rect.x -= 50
self.image = self.image_left
if key[K_RIGHT]:
self.rect.x += 50
self.image = self.image_right
class room1():
#bedroom
def __init__(self):
self.x, self.y = 16, WINDOWHEIGHT/2
self.speed = 3
def draw(self):
background = pygame.image.load("bedroom.jpg").convert()
background = pygame.transform.scale(background, (WINDOWWIDTH, WINDOWHEIGHT))
screen.blit(background, (0, 0))
And this is my main function :
def main():
while True:
for event in pygame.event.get():
player.handle_event.get(event)
player.handle_event(screen)
room1.draw(screen)
player.draw(screen, x, y)
pygame.display.update()
pygame.display.flip()
clock.tick(FPS)
main()
I keep getting the same error :
File "C:\Python32\Project3\proj3pt2.py", line 220, in handle_event
self.image = self.image_down.get_rect()
AttributeError: 'pygame.Surface' object has no attribute 'image_down'
I know it's probably an easy fix, but I don't know where to look for it, and how I messed up. If someone could explain that, it would be much appreciated!
When you have an instance and call one of its methods, the instance gets automatically passed as the first argument, self. So if you have a class MyClass and an instance my_instance and you call its handle_event method, it's the same as calling MyClass.handle_event(my_instance).
In your program you never create an instance of the player class and so you're passing the screen as the self argument directly to the class (the screen is actually a pygame.Surface). That means the self in the handle_event method actually refers to the screen surface and since surfaces don't have an image_down attribute, Python raises an error when the self.image_down.get_rect() part is reached.
To fix this problem, you have to create an instance (also called object) of the player class and must not pass an argument to handle_event (unless you add more parameters to the method):
player_instance = player(x_position, y_position)
Then use the instance inside of the while and event loops:
while True:
player_instance.handle_event()
You also have to create an instance of the room1 class instead of using the class directly.
Here's a complete example with some comments about other problems:
import pygame
pygame.init()
WINDOWWIDTH = 900
WINDOWHEIGHT = 400
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
FPS = 40
clock = pygame.time.Clock()
# Load images once globally and reuse them in the program.
background = pygame.image.load("bedroom.jpg").convert()
background = pygame.transform.scale(background, (WINDOWWIDTH, WINDOWHEIGHT))
temp_image = pygame.image.load("stand_down.png").convert_alpha()
image_down = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standleft.png").convert_alpha()
image_left = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standright.png").convert_alpha()
image_right = pygame.transform.scale(temp_image, (100, 200))
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
super(player, self).__init__()
self.image_down = image_down
self.image_left = image_left
self.image_right = image_right
self.image = self.image_down
# keep position and size in pygame.Rect()
# to use it in collision checking
self.rect = self.image.get_rect(x=x, y=y)
# You don't have to pass x and y, since you already
# use the `self.rect` as the blit position.
def draw(self, screen):
screen.blit(self.image, self.rect)
def handle_event(self):
# These two lines don't make sense.
#self.image = self.image_down.get_rect()
#self.image = pygame.Surface((x, y))
# I guess you want to switch back to image_down.
self.image = self.image_down
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
self.rect.x -= 5
self.image = self.image_left
if key[pygame.K_RIGHT]:
self.rect.x += 5
self.image = self.image_right
class room1():
def __init__(self):
self.x, self.y = 16, WINDOWHEIGHT/2
# Reference to the background image.
self.background = background
def draw(self, screen): # Pass the screen.
screen.blit(self.background, (0, 0))
def main():
# Create player and room instances.
player_instance = player(200, 150)
room1_instance = room1()
while True:
for event in pygame.event.get():
# Users can press the "X" button to quit.
if event.type == pygame.QUIT:
return
player_instance.handle_event()
room1_instance.draw(screen)
player_instance.draw(screen)
# You don't need both update and flip.
# pygame.display.update()
pygame.display.flip()
clock.tick(FPS)
main()
pygame.quit()
Side note: PEP 8 recommends uppercase names for classes, so Player instead of player. Then you could call the instance player.
I suspect you do somewhere something like this
player = player.transform.scale(player.image)
player is Sprite but scale returns Surface - so you replace Sprite with Surface and later you have problems.
(BTW: I saw the same problem in some question few days ago)
If you have to rescale image then do it in __init__ as you already do with some images.
In real game you should create images with correct sizes using any Image Editor so you don't have to use scale()
BTW: in handle_event you do
self.image = self.image_down.get_rect()
self.image = pygame.Surface((x, y))
You assign Rect to Surface (self.image) and later you assing new empty Surface with size x, y. Surface doesn't keep positon, it uses only width, height.
You have self.rect to keep positiona and you already change it with
self.rect.x -= 50
and
self.rect.x += 50
BTW: use UpperCaseNames for classes to make code more readable
class Player(...)
class Room1(...)
Event Stackoverflow knows this rule and it uses light blue color for classes to make code more readable.
More: PEP 8 -- Style Guide for Python Code
BTW: in room1.draw() you read and rescale image again and again - it can slow down program. Do it in room.__init__
I am trying to implement a Python game (aliens.py from the PyGame package) but when I run it, I can't move my player or do any shooting...
I run it on Mac OS X, python3 and have a french keyboard. Could this have anything to do the fact that it does not take any of my keyboard commands?
On the screen of my terminal I see:
^[ (when I press esc),
^[[D (when I press the left arrow),
^[[C (when I press the right arrow),
^[[A (when I press the upwards arrow),
^[[B (when I press the downwards arrow
...
Is this normal? It does not help replacing K_RIGHT with ^[[C.
#!/usr/bin/env python
import random, os.path
#import basic pygame modules
import pygame
from pygame.locals import *
#see if we can load more than standard BMP
if not pygame.image.get_extended():
raise SystemExit("Sorry, extended image module required")
#game constants
MAX_SHOTS = 2 #most player bullets onscreen
ALIEN_ODDS = 22 #ances a new alien appears
BOMB_ODDS = 60 #chances a new bomb will drop
ALIEN_RELOAD = 12 #frames between new aliens
SCREENRECT = Rect(0, 0, 940, 480)
SCORE = 0
main_dir = os.path.split(os.path.abspath(__file__))[0]
def load_image(file):
"loads an image, prepares it for play"
file = os.path.join(main_dir, 'data', file)
try:
surface = pygame.image.load(file)
except pygame.error:
raise SystemExit('Could not load image "%s" %s'%(file, pygame.get_error()))
return surface.convert()
def load_images(*files):
imgs = []
for file in files:
imgs.append(load_image(file))
return imgs
class dummysound:
def play(self): pass
def load_sound(file):
if not pygame.mixer: return dummysound()
file = os.path.join(main_dir, 'data', file)
try:
sound = pygame.mixer.Sound(file)
return sound
except pygame.error:
print ('Warning, unable to load, %s' % file)
return dummysound()
# each type of game object gets an init and an
# update function. the update function is called
# once per frame, and it is when each object should
# change it's current position and state. the Player
# object actually gets a "move" function instead of
# update, since it is passed extra information about
# the keyboard
class Player(pygame.sprite.Sprite):
speed = 10
bounce = 24
gun_offset = -11
images = []
def __init__(self):
pygame.sprite.Sprite.__init__(self, self.containers)
self.image = self.images[0]
self.rect = self.image.get_rect(midbottom=SCREENRECT.midbottom)
self.reloading = 0
self.origtop = self.rect.top
self.facing = -1
def move(self, direction):
if direction: self.facing = direction
self.rect.move_ip(direction*self.speed, 0)
self.rect = self.rect.clamp(SCREENRECT)
if direction < 0:
self.image = self.images[0]
elif direction > 0:
self.image = self.images[1]
self.rect.top = self.origtop - (self.rect.left//self.bounce%2)
def gunpos(self):
pos = self.facing*self.gun_offset + self.rect.centerx
return pos, self.rect.top
class Alien(pygame.sprite.Sprite):
speed = 13
animcycle = 12
images = []
def __init__(self):
pygame.sprite.Sprite.__init__(self, self.containers)
self.image = self.images[0]
self.rect = self.image.get_rect()
self.facing = random.choice((-1,1)) * Alien.speed
self.frame = 0
if self.facing < 0:
self.rect.right = SCREENRECT.right
def update(self):
self.rect.move_ip(self.facing, 0)
if not SCREENRECT.contains(self.rect):
self.facing = -self.facing;
self.rect.top = self.rect.bottom + 1
self.rect = self.rect.clamp(SCREENRECT)
self.frame = self.frame + 1
self.image = self.images[self.frame//self.animcycle%3]
class Explosion(pygame.sprite.Sprite):
defaultlife = 12
animcycle = 3
images = []
def __init__(self, actor):
pygame.sprite.Sprite.__init__(self, self.containers)
self.image = self.images[0]
self.rect = self.image.get_rect(center=actor.rect.center)
self.life = self.defaultlife
def update(self):
self.life = self.life - 1
self.image = self.images[self.life//self.animcycle%2]
if self.life <= 0: self.kill()
class Shot(pygame.sprite.Sprite):
speed = -11
images = []
def __init__(self, pos):
pygame.sprite.Sprite.__init__(self, self.containers)
self.image = self.images[0]
self.rect = self.image.get_rect(midbottom=pos)
def update(self):
self.rect.move_ip(0, self.speed)
if self.rect.top <= 0:
self.kill()
class Bomb(pygame.sprite.Sprite):
speed = 9
images = []
def __init__(self, alien):
pygame.sprite.Sprite.__init__(self, self.containers)
self.image = self.images[0]
self.rect = self.image.get_rect(midbottom=
alien.rect.move(0,5).midbottom)
def update(self):
self.rect.move_ip(0, self.speed)
if self.rect.bottom >= 470:
Explosion(self)
self.kill()
class Score(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.font = pygame.font.Font(None, 20)
self.font.set_italic(1)
self.color = Color('white')
self.lastscore = -1
self.update()
self.rect = self.image.get_rect().move(10, 450)
def update(self):
if SCORE != self.lastscore:
self.lastscore = SCORE
msg = "Score: %d" % SCORE
self.image = self.font.render(msg, 0, self.color)
def main(winstyle = 0):
# Initialize pygame
pygame.init()
if pygame.mixer and not pygame.mixer.get_init():
print ('Warning, no sound')
pygame.mixer = None
# Set the display mode
winstyle = 0 # |FULLSCREEN
bestdepth = pygame.display.mode_ok(SCREENRECT.size, winstyle, 32)
screen = pygame.display.set_mode(SCREENRECT.size, winstyle, bestdepth)
#Load images, assign to sprite classes
#(do this before the classes are used, after screen setup)
img = load_image('player1.gif')
Player.images = [img, pygame.transform.flip(img, 1, 0)]
img = load_image('explosion1.gif')
Explosion.images = [img, pygame.transform.flip(img, 1, 1)]
Alien.images = load_images('alien1.gif', 'alien2.gif', 'alien3.gif')
Bomb.images = [load_image('bomb.gif')]
Shot.images = [load_image('shot.gif')]
#decorate the game window
icon = pygame.transform.scale(Alien.images[0], (32, 32))
pygame.display.set_icon(icon)
pygame.display.set_caption('Pygame Aliens')
pygame.mouse.set_visible(0)
#create the background, tile the bgd image
bgdtile = load_image('background.gif')
background = pygame.Surface(SCREENRECT.size)
for x in range(0, SCREENRECT.width, bgdtile.get_width()):
background.blit(bgdtile, (x, 0))
screen.blit(background, (0,0))
pygame.display.flip()
#load the sound effects
boom_sound = load_sound('boom.wav')
shoot_sound = load_sound('car_door.wav')
if pygame.mixer:
music = os.path.join(main_dir, 'data', 'house_lo.wav')
pygame.mixer.music.load(music)
pygame.mixer.music.play(-1)
# Initialize Game Groups
aliens = pygame.sprite.Group()
shots = pygame.sprite.Group()
bombs = pygame.sprite.Group()
all = pygame.sprite.RenderUpdates()
lastalien = pygame.sprite.GroupSingle()
#assign default groups to each sprite class
Player.containers = all
Alien.containers = aliens, all, lastalien
Shot.containers = shots, all
Bomb.containers = bombs, all
Explosion.containers = all
Score.containers = all
#Create Some Starting Values
global score
alienreload = ALIEN_RELOAD
kills = 0
clock = pygame.time.Clock()
#initialize our starting sprites
global SCORE
player = Player()
Alien() #note, this 'lives' because it goes into a sprite group
if pygame.font:
all.add(Score())
while player.alive():
#get input
for event in pygame.event.get():
if event.type == QUIT or \
(event.type == KEYDOWN and event.key == K_ESCAPE):
return
keystate = pygame.key.get_pressed()
# clear/erase the last drawn sprites
all.clear(screen, background)
#update all the sprites
all.update()
#handle player input
direction = keystate[K_RIGHT] - keystate[K_LEFT]
player.move(direction)
firing = keystate[K_SPACE]
if not player.reloading and firing and len(shots) < MAX_SHOTS:
Shot(player.gunpos())
shoot_sound.play()
player.reloading = firing
# Create new alien
if alienreload:
alienreload = alienreload - 1
elif not int(random.random() * ALIEN_ODDS):
Alien()
alienreload = ALIEN_RELOAD
# Drop bombs
if lastalien and not int(random.random() * BOMB_ODDS):
Bomb(lastalien.sprite)
# Detect collisions
for alien in pygame.sprite.spritecollide(player, aliens, 1):
boom_sound.play()
Explosion(alien)
Explosion(player)
SCORE = SCORE + 1
player.kill()
for alien in pygame.sprite.groupcollide(shots, aliens, 1, 1).keys():
boom_sound.play()
Explosion(alien)
SCORE = SCORE + 1
for bomb in pygame.sprite.spritecollide(player, bombs, 1):
boom_sound.play()
Explosion(player)
Explosion(bomb)
player.kill()
#draw the scene
dirty = all.draw(screen)
pygame.display.update(dirty)
#cap the framerate
clock.tick(40)
if pygame.mixer:
pygame.mixer.music.fadeout(1000)
pygame.time.wait(1000)
pygame.quit()
#call the "main" function if running this script
if __name__ == '__main__': main()
Event KEYDOWN sends values unicode, key, mod and you can display it to see what codes (numeric values) uses your keyboard.
if event.type == KEYDOWN;
print('key:', event.key)
print('unicode:', event.uniconde)
print('mod:', event.mod)
And then you can use them to test your keys and move objects.
It is surely due to keyboard keys problem , just go to this documentation and find out proper keyword for your respective keyboard button:
"https://www.pygame.org/docs/ref/key.html"
I'm working on a game for class and this is what we've learned to do so far. I'm trying to get the sprites to stay onscreen with clamp_ip, but it keeps giving me an error message that "Butterfly instance has no attribute clamp_ip." Is there a different way I should be keeping the butterflies onscreen?
This first bit is just setting up pygame and the butterfly class (where I included a line to define a rectangle for the butterflies), I've highlighted where I'm guessing the potential errors are below.
This should be ok.
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
playground = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Butterflies')
screenRect = playground.get_rect()
steps = 1
class Butterfly:
def __init__(self):
self.x = random.randint(0, SCREEN_WIDTH)
self.y = random.randint(0, SCREEN_HEIGHT)
self.image_Butterfly = pygame.image.load('butterflya.png')
self.image_ButterflyB = pygame.image.load('butterflyb.png')
self.height = self.image_Butterfly.get_height()
self.width = self.image_Butterfly.get_width()
self.rect = (self.width, self.height)
clock = pygame.time.Clock()
fps = 10
net = []
for i in range (15):
butterflyInstance = Butterfly()
net.append(butterflyInstance)
playground.fill(cyan)
Game_Over = False
while not Game_Over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Game_Over = True
This is where I'm guessing I messed up. I tried to use the clamp_ip function at the end of this loop
for butterflyInstance in net:
butterflyInstance.x += random.randint(-10, 10)
butterflyInstance.y += random.randint(-10,10)
if steps % 2 == 0:
playground.blit(butterflyInstance.image_Butterfly, (butterflyInstance.x, butterflyInstance.y))
steps += 1
else:
playground.blit(butterflyInstance.image_ButterflyB, (butterflyInstance.x, butterflyInstance.y))
steps +=1
butterflyInstance.clamp_ip(screenRect)
Thank you so much!
See PyGame doc pygame.Rect()
clamp_ip is pygame.Rect method so you have to use butterflyInstance.rect.clamp_ip()
But you have to use self.rect.x, self.rect.y, self.rect.width, self.rect.height instead of self.x, self.y, self.width, self.height to keep position and size of object.
And use butterflyInstance.rect.x, butterflyInstance.rect.y, butterflyInstance.rect.width, butterflyInstance.rect.height
instead of butterflyInstance.x, butterflyInstance.y, butterflyInstance.width, butterflyInstance.height
PyGame use pygame.Rect in many places - it is usefull. For example: you can use rect.right instead of rect.x + rect.width, or rect.center = screenRect.center to center object on screen.
I'm just learning Python, and as one of the basic challenges that were suggested to me by friends I've been working on an alarm clock. I successfully made an alarm clock that played a .wav sound at a predetermined time. Now I've been using Pygame for a GUI, and it all worked great, until I had to set the buttons to adjust the alarm time. See when I compare the alarm time to the clock time, the clock time is in string form, so the alarm time has to be as well. But the buttons are unable to + or - from a string, so I'm kind of stuck. I tried ways of turning it into a string, but everything has been fairly unsuccessful so far. Wondering if anyone here had a suggestion.
Here's the code:
#!/usr/bin/python
import os.path, sys, datetime, time
import os, sys, math
import pygame, random
from pygame.locals import *
main_dir = os.path.split(os.path.abspath(__file__))[0]
data_dir = os.path.join(main_dir, 'data')
currenttime = datetime.datetime.now()
clocktime = currenttime.strftime("%H:%M")
alarmtime = "13:23"
pygame.init()
#Screen and background
width, height = 600, 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Alarm Clock")
background = pygame.image.load(os.path.join(data_dir, 'diamondplate.jpg'))
background = pygame.transform.scale(background, (width, height))
#Current time
font = pygame.font.Font(None, 250)
text = font.render("%s" % clocktime, True, (255,140,0), (0,0,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery - 200
#Alarm time
text2 = font.render("%s" % '00:00', True, (255,140,0), (0,0,0))
text2Rect = text2.get_rect()
text2Rect.centerx = screen.get_rect().centerx
text2Rect.centery = screen.get_rect().centery + 200
#Alarm noise
def alarmsound(file_path=os.path.join(main_dir, 'data', 'boom.wav')):
pygame.mixer.init(11025)
sound = pygame.mixer.Sound(file_path)
channel = sound.play()
pygame.time.wait(1000)
#Image load function
def load_image(file):
file = os.path.join(data_dir, file)
surface = pygame.image.load(file)
return surface.convert_alpha()
#Hour arrow up
class Hourup(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,self.groups)
image = load_image('arrowup.png')
image = pygame.transform.scale(image, (85,85))
self.image = image
self.rect = self.image.get_rect()
surface = pygame.display.get_surface()
self.area = surface.get_rect()
self.rect.bottomleft = text2Rect.topleft
def click_check(self,eventpos):
if self.rect.collidepoint(eventpos):
pass
def update(self):
pass
#Hour arrow down
class Hourdown(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,self.groups)
image = load_image('arrowdown.png')
image = pygame.transform.scale(image, (85,85))
self.image = image
self.rect = self.image.get_rect()
surface = pygame.display.get_surface()
self.area = surface.get_rect()
self.rect.bottom = text2Rect.top
self.rect.left = 159
def click_check(self,eventpos):
if self.rect.collidepoint(eventpos):
pass
def update(self):
pass
#Minute arrow up
class Minuteup(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,self.groups)
image = load_image('arrowup.png')
image = pygame.transform.scale(image, (85,85))
self.image = image
self.rect = self.image.get_rect()
surface = pygame.display.get_surface()
self.area = surface.get_rect()
self.rect.bottomright = (442,414)
def click_check(self,eventpos):
if self.rect.collidepoint(eventpos):
pass
def update(self):
pass
#Minute arrow down
class Minutedown(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,self.groups)
image = load_image('arrowdown.png')
image = pygame.transform.scale(image, (85,85))
self.image = image
self.rect = self.image.get_rect()
surface = pygame.display.get_surface()
self.area = surface.get_rect()
self.rect.bottomright = text2Rect.topright
def click_check(self,eventpos):
if self.rect.collidepoint(eventpos):
pass
def update(self):
pass
#Groups
allsprites = pygame.sprite.Group()
Hourup.groups = allsprites
Hourdown.groups = allsprites
Minutedown.groups = allsprites
Minuteup.groups = allsprites
hourup = Hourup()
hourdown = Hourdown()
minutedown = Minutedown()
minuteup = Minuteup()
clickableobjects = [hourup, hourdown, minutedown, minuteup]
def main():
while 1:
currenttime = datetime.datetime.now()
clocktime = currenttime.strftime("%H:%M")
screen.blit(background,(0,0))
text = font.render("%s" % clocktime, True, (255,140,0), (0,0,0))
text2 = font.render("%s" % alarmtime, True, (255,140,0), (0,0,0))
screen.blit(text,textRect)
screen.blit(text2,text2Rect)
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
sys.exit()
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
for object in clickableobjects:
object.click_check(event.pos)
if clocktime == alarmtime and soundcheck = False:
alarmsound()
soundcheck = True
allsprites.draw(screen)
allsprites.update()
pygame.display.update()
pygame.display.flip
if __name__ == '__main__':
main()
You are looking for strptime() which will convert a string to a datetime instance.
see here for how to properly use it.
Comparing two datetime instances will give you a timedelta instance which you can read about here. Essentially it will give you the difference between the two times to the nearest milisecond.
Learn everything you can about the datetime, time, and calendar modules. Once you learn those dealing with times and dates in python becomes really easy.