How can I go about generating platforms to corresponding "E"'s of the level without the Sprite class? I tried some different methods but none of them seemed to work. Basically, the idea is that the "E"'s should just make 50x50 blocks in a row.
import pygame
pygame.init()
display_width = 900
display_height = 600
size = (display_width, display_height)
black = (0,0,0)
white = (255,255,255)
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
platx = 350
platy = 150
platw = 50
plath = 50
clock = pygame.time.Clock()
platx = 600
platy = 350
platw = 50
plath = 50
level = ["E","E","E","E","E","E","E","E","E","E"]
class Platform:
def __init__(self, platx, platy, platw, plath):
self.platx = platx
self.platy = platy
self.platw = platw
self.plath = plath
def draw(self):
pygame.draw.rect(screen, black, [self.platx, self.platy, self.platw, self.plath])
platforms = Platform(platx, platy, platw, plath)
game_exit = False
while not game_exit:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
#why doesnt a loop like this work?
#for i in level:
# if i == "E":
# platforms.draw()
# platx += display_width *.1
#shouldn't it be placing platforms 1/10 of the display_width from the starting platx?
screen.fill(white)
pygame.display.update()
If I understand your code correctly, this is the code that needs to be fixed:
#why doesnt a loop like this work?
#for i in level:
# if i == "E":
# platforms.draw()
# platx += display_width *.1
#shouldn't it be placing platforms 1/10 of the display_width from the starting platx?
The problem with this is that platx was already passed as an argument to Platform.__init__. Since the variable platform.platx no longer has a weakref to the global platx (being passed as an argument), they no longer match. Thus, instead of incrementing platx, `platform.platx should be incremented.
Also, you need to reset platform.platx after drawing each row.
Related
The following code generates random x,y coordinates, appending the coordinates to a list, then runs a for-loop through the list to blit star images to the screen. The same stars are constantly being redrawn while the code is running, but they're in the same location, so the screen looks static. Here is the code.
import time
import pygame
from random import randint
pygame.init()
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("My God, it's full of stars!")
med_star_img = pygame.image.load('images/medium_star.png')
tiny_star_img = pygame.image.load('images/tiny_star.png')
black = (0,0,0)
white = (255,255,255)
gray = (50,50,50)
tiny_stars_width = tiny_star_img.get_width()
tiny_stars_height = tiny_star_img.get_height()
med_stars_width = med_star_img.get_width()
med_stars_height = med_star_img.get_height()
tiny_stars_location = []
med_stars_location = []
clock = pygame.time.Clock()
running = True
gameDisplay.fill(gray)
# create random coordinates for stars
for i in range(25):
tiny_stars_location.append(pygame.Rect(randint(1,800),randint(1,600),tiny_stars_width,tiny_stars_height))
for i in range(10):
med_stars_location.append(pygame.Rect(randint(1,800),randint(1,600),med_stars_width,med_stars_height))
def make_med_star(x,y):
gameDisplay.blit(med_star_img, (x,y))
def make_tiny_star(x,y):
gameDisplay.blit(tiny_star_img, (x,y))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for star in med_stars_location:
make_med_star(star.x,star.y)
for star in tiny_stars_location:
make_tiny_star(star.x,star.y)
pygame.display.flip()
time.sleep(1)
clock.tick(60)
pygame.quit()
quit()
I'd like the stars to occasionally blink, which I think would be done by randomly removing one or two stars from the stars_location list during the main loop before adding them back when the loop comes back around. The loop probably executes very fast, but I think I can add a delay. Any help here would be greatly appreciated.
You can save a boolean for each star. If the value is True the star is visible.
Example for saving star data: (I wouldn't use the pygame.Rect and instead a simple list)
for i in range(25):
tiny_stars_location.append([randint(1,800),randint(1,600),tiny_stars_width,tiny_stars_height, True])
Also you should not use time.sleep in a pygame program. It does not delay a task. I delays the program. So you have to wait a whole second to close the program or interact with it in any way.
A lazy but working approach would be just to use randomness. You could just get a random number with random.randint(0, n), if it is 0 you set the boolean value of the star to True or False, depending on what state it currently is. You can set the variable n to some number like
n = maximum fps * average seconds before the star is hidden/shown
An other thing you probably just forgot is to clear the window in the loop with gameDisplay.fill(gray).
Your finished code could look like this:
import time
import pygame
from random import randint
pygame.init()
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("My God, it's full of stars!")
med_star_img = pygame.image.load('images/medium_star.png')
tiny_star_img = pygame.image.load('images/tiny_star.png')
black = (0,0,0)
white = (255,255,255)
gray = (50,50,50)
tiny_stars_width = tiny_star_img.get_width()
tiny_stars_height = tiny_star_img.get_height()
med_stars_width = med_star_img.get_width()
med_stars_height = med_star_img.get_height()
tiny_stars_location = []
med_stars_location = []
clock = pygame.time.Clock()
running = True
gameDisplay.fill(gray)
# create random coordinates for stars
for i in range(25):
tiny_stars_location.append([randint(1,800),randint(1,600),tiny_stars_width,tiny_stars_height, True])
for i in range(10):
med_stars_location.append([randint(1,800),randint(1,600),med_stars_width,med_stars_height, True])
def make_med_star(x,y):
gameDisplay.blit(med_star_img, (x,y))
def make_tiny_star(x,y):
gameDisplay.blit(tiny_star_img, (x,y))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for star in med_stars_location:
if star[2]:
make_med_star(star[0], star[1])
if not randint(0, 300): # 300 / 60(fps) = 5 -> every 5 seconds on average
star[2] = not star[2] # inverse
for star in tiny_stars_location:
if star[2]:
make_tiny_star(star[0], star[1])
if not randint(0, 300): # 300 / 60(fps) = 5 -> every 5 seconds on average
star[2] = not star[2] # inverse
pygame.display.flip()
#time.sleep(1) <- never do this in pygame
clock.tick(60)
gameDisplay.fill(gray) # reset display
pygame.quit()
I have a single battery image appearing once here and it moves from right to left then goes away. I want batteries constantly coming and going until the player hits one of them.
My question is how do I get the batteries to keep on coming until a player hits it? I want them to appear maybe 100 units apart.
from pygame import *
import os
import random
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d, %d" %(0, 0)
init()
#set screen size
size = width, height = 800, 600
screen = display.set_mode(size)
#set fonts
fontGame=font.SysFont("Times New Roman", 30)
fontBack=font.SysFont("Ariel", 30)
fontTitle=font.SysFont("Ariel", 100)
fontResearch=font.SysFont ("Times New Roman", 18)
#set button and page to 0
button = 0
page=0
#setting colours
BLACK = (0, 0, 0)
RED = (255,0,0)
GREEN = (0, 255, 0)
BLUE = (106,186,232)
#loading image
backgroundPic=image.load("Background.jpg")
backgroundGame=image.load("gameBackground.jpg")
backgroundGame=transform.scale(backgroundGame,(800,600))
battery=image.load("Battery.png")
battery=transform.scale(battery,(100,100))
backgroundx=0
playerPic=image.load("player.png")
playerPic=transform.scale(playerPic,(70,70))
batteryx=[]
#defining what is going to be shown on the screen
def drawScene(screen, button,page,locationx,locationy):
global batteryx
mx, my = mouse.get_pos() #will get where the mouse is
#if the user does nothing
if page==0:
draw.rect(screen, BLACK, (0,0, width, height))
screen.fill(BLACK)
rel_backgroundx= backgroundx % backgroundGame.get_rect().width
screen.blit(backgroundGame, (rel_backgroundx - backgroundGame.get_rect().width,0))
if rel_backgroundx < width:
screen.blit (backgroundGame, (rel_backgroundx,0))
screen.blit(playerPic,(locationx,locationy))
screen.blit(battery,(batteryx,420))
batteryx-=1
display.flip()
return page
#def collision (battery, playerPic):
#if battery.colliderect(playerPic):
#return True
#return False
running = True
myClock = time.Clock()
KEY_LEFT= False
KEY_RIGHT= False
KEY_UP= False
KEY_DOWN= False
locationx=0
jumping=False
accel=20
onGround= height-150
locationy=onGround
batteryx=random.randrange(50,width,10)
# Game Loop
while running:
button=0
print (KEY_LEFT, KEY_RIGHT)
for evnt in event.get(): # checks all events that happen
if evnt.type == QUIT:
running=False
if evnt.type == MOUSEBUTTONDOWN:
mx,my=evnt.pos
button = evnt.button
if evnt.type== KEYDOWN:
if evnt.key==K_LEFT:
KEY_LEFT= True
KEY_RIGHT= False
if evnt.key==K_RIGHT:
KEY_RIGHT= True
KEY_LEFT= False
if evnt.key==K_UP and jumping==False:
jumping=True
accel=20
if evnt.key== K_DOWN:
KEY_DOWN= True
KEY_UP= False
if evnt.type==KEYUP:
if evnt.key==K_LEFT:
KEY_LEFT= False
if evnt.key==K_RIGHT:
KEY_RIGHT= False
if evnt.key==K_DOWN:
KEY_DOWN=False
if KEY_LEFT== True:
locationx-=10
backgroundx+=10
if KEY_RIGHT== True:
locationx+=10
backgroundx-=10
if jumping==True:
locationy-=accel
accel-=1
if locationy>=onGround:
jumping=False
locationy=onGround
#player cannot move off screen
if locationx<0:
locationx=0
if locationx>400:
locationx=400
#if collision(battery, playerPic)==True:
#screen.fill(BLACK)
page=drawScene(screen,button,page,locationx,locationy)
myClock.tick(60) # waits long enough to have 60 fps
if page==6: #if last button is clicked program closes
running=False
quit()
Create a list of rects which serve as the positions of the batteries. Use for loops to update the rects and blit the battery image at the rects. Remove rects that have left the screen and append new rects to create new batteries
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
battery_image = pg.Surface((30, 50))
battery_image.fill(pg.Color('sienna1'))
# Append pygame.Rect objects to this list.
batteries = []
batteries.append(battery_image.get_rect(topleft=(700, 100)))
battery_speed = -5
battery_timer = 40
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
# A simple frame based timer.
battery_timer -= 1
if battery_timer <= 0:
battery_timer = 40
# After 40 frames a new rect gets appended to the list.
batteries.append(battery_image.get_rect(topleft=(700, 100)))
temp_list = []
# Iterate over the rects to update them.
for battery_rect in batteries:
battery_rect.x += battery_speed
# Rects with x <= 50 won't be appended to the temp_list.
if battery_rect.x > 50:
temp_list.append(battery_rect)
# Assign the list with the remaining rects to the batteries variable.
batteries = temp_list
# Blit everything.
screen.fill(BG_COLOR)
for battery_rect in batteries:
screen.blit(battery_image, battery_rect)
pg.display.flip()
clock.tick(30)
pg.quit()
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 trying to make a function when the mouse button is up, it changes the picture of the ghosts to one single image.
Problem being, I have no idea what to call upon (Hence the ??? in the script). It's hard because the ghosts are created via a loop. Can anyone possibly help?
Maybe i need to change the ghosts into sprites? could you help with that too?
import pygame
import random
import sys
class Ball:
def __init__(self,X,Y,imagefile):
self.velocity = [3,3]
self.ball_image = pygame.image.load (imagefile). convert() ### i want this image to change
self.ball_boundary = self.ball_image.get_rect (center=(X,Y))
self.sound = pygame.mixer.Sound ('Thump.wav')
if __name__ =='__main__':
width = 800
height = 600
background_colour = 0,0,0
GHOST_IMAGE = ["images/blue-right.png", "images/red-right.png", "images/orange-right.png", "images/pink-right.png"]
GHOST_IMAGETWO = ["images/blue-left.png", "images/red-left.png", "images/orange-left.png", "images/pink-left.png"]
pygame.init()
frame = pygame.display.set_mode((width, height))
pygame.display.set_caption("Bouncing Ball animation")
num_balls = 4
ball_list = []
for i in range(num_balls):
ball_list.append( Ball(random.randint(0, width),random.randint(0, height), (GHOST_IMAGE[i]) ))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit(0)
elif event.type == pygame.MOUSEBUTTONUP:
??? = pygame.image.load("images/vulnerable.png").convert() ###i know that this is where and what i need to change it to, but dont know what instance name to call upon.
frame.fill(background_colour)
for ball in ball_list:
if ball.ball_boundary.left < 0 or ball.ball_boundary.right > width:
ball.sound.play()
ball.velocity[0] = -1 * ball.velocity[0]
if ball.ball_boundary.top < 0 or ball.ball_boundary.bottom > height:
ball.sound.play()
ball.velocity[1] = -1 * ball.velocity[1]
ball.ball_boundary = ball.ball_boundary.move (ball.velocity)
frame.blit (ball.ball_image, ball.ball_boundary)
pygame.display.flip()
One way is to just iterate over the ball_list and change each ball:
elif event.type == pygame.MOUSEBUTTONUP:
image = pygame.image.load("images/vulnerable.png").convert()
for ball in ball_list:
ball.ball_image = image
Another way would be implement the image-changing behaviour directly in the Ball class:
class Ball:
def __init__(self,X,Y,imagefile):
self.vulnerable = False
self.velocity = [3,3]
self.normal_ball_image = pygame.image.load (imagefile). convert()
self.v_ball_image = pygame.image.load("images/vulnerable.png").convert()
self.ball_image = self.normal_ball_image
self.ball_boundary = self.ball_image.get_rect (center=(X,Y))
self.sound = pygame.mixer.Sound ('Thump.wav')
def toggle(self):
self.vulnerable = not self.vulnerable
self.ball_image = self.v_ball_image if self.vulnerable else self.normal_ball_image
And in your loop:
elif event.type == pygame.MOUSEBUTTONUP:
for ball in ball_list:
ball.toggle()
I am trying to make walking animations for images returned from a sprite sheet.
I am using .set_clip to return a portion of the sprite sheet. Everything looks like it should work
But the .set_clip is returning the first Rect value in the list that I provide, rather than the item in the list that I call for.
My Code
import pygame, sys
from pygame.locals import *
xList = (6, 27,48,69)
yList = (24,24,24,24)
wList = (21,21,21,21)
hList = (32,32,32,32)
ani_pos = list(zip(xList, yList, wList, hList))
sprite_num = 0
class Player:
def __init__(self):
playerSheet = pygame.image.load('MainChar1.png').convert() # load sprite sheet
playerSheet.set_clip(pygame.Rect(ani_pos[sprite_num]))
self.player = playerSheet.subsurface(playerSheet.get_clip())
self.x = 320
self.y = 240
def draw(self, DISPLAYSURF):
DISPLAYSURF.blit(self.player, (self.x, self.y))
self.player.set_colorkey(255, 0, 255)# set sprite background invisible
class Background:
def __init__(self):
dirtTile = pygame.image.load('DirtBackground.png').convert()
dirtTile.set_clip(pygame.Rect(0, 0, 863, 1103))
self.background = dirtTile.subsurface(dirtTile.get_clip())
self.x = -111
self.y = -311
def draw(self, DISPLAYSURF):
DISPLAYSURF.blit(self.background, (self.x, self.y))
pygame.init()
FPS = 30
FPSCLOCK = pygame.time.Clock()
# set up the window
WINDOWWIDTH = 640 # size of windows' width in pixels
WINDOWHEIGHT = 480 # size of windows' height in pixels
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('farm game')
player = Player()
background = Background()
pygame.key.set_repeat(1,0) # (mSec to begin repeat, mSec between repeats)
running = True
while running: # the main game loop
DISPLAYSURF.fill (255,255,255)
background.draw(DISPLAYSURF)
player.draw(DISPLAYSURF)
pygame.display.flip()
FPSCLOCK.tick(FPS)
for event in pygame.event.get(): # event handling loop
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
running = False
elif event.type == KEYDOWN:
if event.key == K_d:
background.x -= 4
sprite_num = 2
I am using .set_clip to return a portion of the sprite sheet.
No, you don't. You use subsurface to return a portion of the sprite sheet.
I don't know what you think what set_clip does, but it's probably not what it actually does:
This is a rectangle that represents the only pixels on the Surface that can be modified.
Better explained at the SDL docs:
Sets the clipping rectangle for a surface. When this surface is the destination of a blit, only the area within the clip rectangle will be drawn into.
But the .set_clip is returning the first Rect value in the list that I provide, rather than the item in the list that I call for.
set_clip does not return any Rect value of any list at all.
When you call pygame.Rect(ani_pos[sprite_num]), you're creating a Rect with the values in the list ani_pos at index sprite_num, and sprite_num is 0 when the __init__ method is called.
You store your Surface that you create in the __init__ method in the player field, but you never actually change it. If you want to create some kind of animation, you should change it every n frames. You change sprite_num to 2, but that does not do anything since you never use that value again.