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()
Related
I was trying to create a function that will load an image and move the image downwards while loading another image and still moving with the same speed as the first. But I don't know how to do it, all I can do for now is to load the next image when the y coordinate of the first is at 500
def aliens():
s = 0
i = "345678"
c = 1
b = int("".join(random.sample(i, c)))
h = 1
while h < 2:
while s <= b:
alien = pygame.image.load("ali.jpg")
alien = pygame.transform.scale(alien, (100, 100))
pos = "0123456789"
l = 3
x = int("".join(random.sample(pos, l)))
y = 0
if x > 500:
h = 3
crash = False
s +=1
while not crash :
scn.blit(alien, (x, y))
y +=2
pygame.display.flip()
if y > 500:
crash = True
The core of your problem is the fact that you are trying to do too many things in the same function. Try to follow the SRP (Single Responsability Principle).
Personnally I would use OOP (Object Oriented Programming) here but I don't know if you are familar with the concept, so first let's stick to the basics.
Here is how I would separate things up, if I wasn't allowed to use OOP:
First I would define two constants:
ALIEN_SIZE = 100
ALIEN_IMG = pg.image.load("green_square.png").convert()
ALIEN_IMG = pg.transform.scale(ALIEN_IMG, (ALIEN_SIZE, ALIEN_SIZE))
Since you are always using the same values, there is no need to load your image all the time. Loading your image just once will have a very positive impact on game's performances.
(Note that I used a diffrent image since you did not provide the image you use but feel free to put the link to your image back)
Then I would define an alien list:
aliens = []
I don't know how you plan to spawn aliens in your project ? For this example I used a custom event with a timer:
# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)
# This function handles all pygame events
def handle_evt():
for evt in pg.event.get():
if evt.type == pg.QUIT:
exit()
if evt.type == SPAWN_ALIEN:
spawn_alien()
# This function spawns an alien
def spawn_alien():
pos = [rd.randint(0, screen.get_width() - ALIEN_SIZE), 0]
aliens.append(pos)
To make aliens move, I use a update() function:
# update aliens position and check if they leave the screen
def update():
for alien in aliens:
move_alien(alien)
if out_of_screen(alien):
kill_alien(alien)
# This function update alien's y position
def move_alien(alien):
alien[1]+=1
# This function remove the given alien from the aliens list
def kill_alien(alien):
aliens.remove(alien)
# This function returns True if the given position is outside screen's boundries
def out_of_screen(pos):
x, y = pos
if x < 0 or x > screen.get_width():
return True
elif y < 0 or y > screen.get_height():
return True
return False
Finally to render things :
def draw():
# Clear screen
screen.fill((0,0,0))
# Draw aliens
for alien in aliens:
screen.blit(ALIEN_IMG, alien)
Here is the full code, so you can see how everything is interacting :
# General imports
import pygame as pg
import random as rd
import sys
# Init
pg.init()
# Vars & consts
screen = pg.display.set_mode((500, 500))
pg.display.set_caption("Example")
FPS = 60
clock = pg.time.Clock()
ALIEN_SIZE = 100
ALIEN_IMG = pg.image.load("green_square.png").convert()
ALIEN_IMG = pg.transform.scale(ALIEN_IMG, (ALIEN_SIZE, ALIEN_SIZE))
# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)
# Main functions
def update():
for alien in aliens:
move_alien(alien)
if out_of_screen(alien):
kill_alien(alien)
def draw():
# Clear screen
screen.fill((0,0,0))
# Draw aliens
for alien in aliens:
screen.blit(ALIEN_IMG, alien)
def handle_evt():
for evt in pg.event.get():
if evt.type == pg.QUIT:
exit()
if evt.type == SPAWN_ALIEN:
spawn_alien()
def exit():
pg.quit()
sys.exit()
# Other functions
def spawn_alien():
pos = [rd.randint(0, screen.get_width() - ALIEN_SIZE), 0]
aliens.append(pos)
def move_alien(alien):
alien[1]+=1
def kill_alien(alien):
aliens.remove(alien)
def out_of_screen(pos):
x, y = pos
if x < 0 or x > screen.get_width():
return True
elif y < 0 or y > screen.get_height():
return True
return False
# Main loop
if __name__ == '__main__':
aliens = []
spawn_alien()
while True:
handle_evt()
update()
draw()
clock.tick(FPS)
pg.display.flip()
And just in case, here is an OOP approach :
# General imports
import pygame as pg
import random as rd
import sys
# Init
pg.init()
# Vars
screen = pg.display.set_mode((500, 500))
pg.display.set_caption("Example")
FPS = 60
clock = pg.time.Clock()
# Class
class Alien():
LIST = []
SIZE = 100
IMG = pg.image.load("green_square.png").convert()
IMG = pg.transform.scale(IMG, (SIZE, SIZE))
def __init__(self, screen_width):
self.img = Alien.IMG
self.pos = (rd.randint(0, screen_width - Alien.SIZE), 0)
# Add alien to the list
Alien.LIST.append(self)
def move(self):
x, y = self.pos
self.pos = (x, y+1)
def has_crashed(self, boundries):
x, y = self.pos
if x < 0 or x > boundries[0]:
return True
elif y < 0 or y > boundries[1]:
return True
return False
def kill(self):
Alien.LIST.remove(self)
# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)
# Main functions
def update():
for alien in Alien.LIST:
alien.move()
if alien.has_crashed(screen.get_size()):
alien.kill()
def draw():
# Clear screen
screen.fill((0,0,0))
# Draw aliens
for alien in Alien.LIST:
screen.blit(alien.img, alien.pos)
def handle_evt():
for evt in pg.event.get():
if evt.type == pg.QUIT:
exit()
if evt.type == SPAWN_ALIEN:
spawn_alien()
def exit():
pg.quit()
sys.exit()
# Other functions
def spawn_alien():
Alien(screen.get_width())
# Main loop
if __name__ == '__main__':
while True:
handle_evt()
update()
draw()
clock.tick(FPS)
pg.display.flip()
I hope all those informations can help you solve your problem. It's hard to know if this, really is the behavior you wanted for your aliens. That's because your variables names are not exactly explicit. One letter variable names are rarely a good idea. But anyway even if you need them to move a little diffrently, you can take inspiration of this code organization.
Have fun !
I am new to python and wanted to create a game to test some knowledge. Please bare with my mistakes. I would also really appreciate an example written out if possible so I can wrap my head around the concept.
I couldn't figure out how to post the entire code without formatting nightmares so I put it in github sorry if this is against terms!
I removed most of the dialogue because it was very very long.
Some background about the same:
It was written as a text-based only game first, then I heard about pygame wanted to figure out how to put the game into the window. So first I created all of the code, which ran perfectly fine even with sound effects / music, but then after trying to figure out pygame's game loop, I can't figure out how to change the background image.
I have 5 scenes that I want 5 images for, that change when I change the scene with user input. Even now, the music changes, but the background images don't change after blitting the first one in the 'naming' scene. I don't really understand how the pygame loop works in conjunction with the game engine I have currently. I know it's looping through the pygame loop as I tested it with printing things, but when trying to add images or saying if scene == naming: blit image, it doesn't work. I also tried putting the images into each of the scenes. I also tried putting the images into a class called background with all 5 scenes and images to each. Can't figure it out.
Any help would be greatly appreciated!
-M
Here is an example of how to use scenes. This is not the only way of doing it, but i though it would be easy to use/understand. I also noticed in your code that you used input(). which is annoying if your using a window, so i also added a button and a textbox input that kinda works.
import pygame as pg
pg.init() # initialize the pg
win = pg.display.set_mode((1080, 720)) # create the game window
pg.display.set_caption("Puppy Love")
white = (255,255,255)
black = (0,0,0)
clock = pg.time.Clock()
fps = 60
class Scene:
def __init__(self):
self.sceneNum = 1
def Scene_1(self):
win.fill(white)
if next_scene_button.draw(): #if clicked button
self.sceneNum += 1
name_Box.Draw()
#anything else you want to draw
def Scene_2(self):
win.fill((0,0,255))
if next_scene_button.draw():
self.sceneNum = 1
#...
def Draw_Scene(self):
if self.sceneNum == 1:
self.Scene_1()
elif self.sceneNum == 2:
self.Scene_2()
class Button:
def __init__(self,x,y,w,h,text):
self.x = x
self.y = y
self.w = w
self.h = h
self.text = text
self.font = pg.font.Font(pg.font.match_font("Calibri"),20)
def draw(self):
button_clicked = False
col = (150,150,150)
if mouse_pos[0] > self.x and mouse_pos[0] < self.x + self.w:
if mouse_pos[1] > self.y and mouse_pos[1] < self.y + self.h:
col = (200,200,200)
if click:
button_clicked = True
pg.draw.rect(win,col,(self.x,self.y,self.w,self.h))
obj = self.font.render(self.text,True, black)
win.blit(obj,(self.x + (self.w-obj.get_width())//2,self.y + (self.h-obj.get_height())//2)) #center the text
return button_clicked #return if the button was clicked or not
class TextBox:
def __init__(self,x = 0, y = 0, w = 0, h = 0, text = "", background = False, font_size = 30, font = "Calibri", text_colour = (0,0,0)):
self.x = x
self.y = y
self.w = w
self.h = h
self.text_colour = text_colour
self.text = text
self.background = background
self.font = pg.font.Font(pg.font.match_font(font),font_size)
def Add_char(self,key):
if key == 8:
self.text = self.text[:-1]
else:
char = pg.key.name(key)
self.text += char
def Draw(self):
if self.background:
pg.draw.rect(win, self.background, (self.x,self.y,self.w,self.h))
obj = self.font.render(self.text,True,self.text_colour)
win.blit(obj,(self.x,self.y))
def Get_pos(self):
return (self.x,self.y)
name_Box = TextBox(x=100, y=200, w=150, h=40, background=(200,200,200))
Scenes = Scene()
next_scene_button = Button(400,400,100,50,"next scene")
click = False
mouse_pos = [0,0]
running = True
while running:
clock.tick(fps)
Scenes.Draw_Scene()
mouse_pos = pg.mouse.get_pos()
click = False
pg.display.update() #no diference between .flip() and .update()
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
running = False
if event.type == pg.MOUSEBUTTONDOWN:
click = True
if event.type == pg.KEYDOWN:
if Scenes.sceneNum == 1:
name_Box.Add_char(event.key)
The main thing to take away from this is to only use one pygame.display.flip(). Hopefully you can use this to improve your program
I'm new to classes, and this is my third attempt at making one. I've ran into a NameError which I really have no idea how to solve. Take a look at my program and see if you can help.
import random
import math
import pygame
import pickle
# initialise pygame
pygame.init()
# player class
class player(object):
def __init__(self, playerimage, playerX, playerY = 700, playerX_change = 0):
self.playerimage = pygame.image.load("Main Player.png")
self.playerX = 365
self.playerY = 700
self.playerX_change = 0
# laser class
# ready - bullet not on screen
# fire - bullet is shown on screen and is moving
class laser(object):
def __init__(self, laserimage, laserX, laserY, laserY_change):
self.laserimage = pygame.image.load("laser.png")
self.laserX = 0
self.laserY = 700
self.laserY_change = 10
self.laser_state = "ready"
# alien player / random movement = random.randint()
class alien(object):
def __init__(self, alienimage, alienX, alienY, alienX_change, alienY_change, amount_aliens):
self.alienimage = pygame.image.load("alien.png")
self.alienX = []
self.alienY = []
self.alienX_change = []
self.alienY_change = []
self.amount_aliens = 10
for i in range(ufo.amount_aliens):
ufo.alienimage.append(pygame.image.load('alien.png'))
ufo.alienX.append(random.randint(0, 735))
ufo.alienY.append(random.randint(50, 200))
ufo.alienX_change.append(3)
ufo.alienY_change.append(7)
score = 0
# define player
def main_player(x, y):
screen.blit(male.playerimage, (x, y))
# define laster
def fire_laser(x, y):
lasr.laser_state = "fire"
screen.blit(lasr.laserimage, (x + 16, y + 10))
# define alien
def alien(x, y, i):
screen.blit(ufo.alienimage[i], (x, y))
# collision detection
def hascollision(alienX, alienY, laserX, laserY):
distance = math.sqrt((math.pow(alienX - laserX, 2)) + (math.pow(alienY - laserY, 2)))
if distance < 27:
return True
else:
return False
#frames per second
clock = pygame.time.Clock()
# background
background = pygame.image.load('stars.png')
# display and screen title/icon
(width, height) = (800, 800)
screen = pygame.display.set_mode((width, height))
flip = pygame.display.flip()
pygame.display.set_caption("space fighters")
pygame.event.get()
icon = pygame.image.load('logo.png')
pygame.display.set_icon(icon)
from sys import exit
ufo = alien()
lasr = laser(0, 700, 32, 32)
male = player(365, 700,)
# loop of functions
executed = True
while executed:
screen.fill((63, 62, 63))
# image background
screen.blit(background, (0, 0))
for event in pygame.event.get():
# if key pressed, check which input, right or left?
if event.type == pygame.KEYDOWN:
print("key pressed")
if event.key == pygame.K_a:
male.playerX_change = -6
if event.key == pygame.K_s:
male.playerX_change = 6
if event.type == pygame.KEYUP:
if event.key == pygame.K_a or event.key == pygame.K_s:
male.playerX_change = 0
if event.key == pygame.K_SPACE:
if lasr.laser_state is "ready":
lasr.laserX = male.playerX
fire_laser(lasr.laserX, lasr.laserY)
#frames per second is 60fps
clock.tick(60)
# bounrary algorithm, prevents player moving out/enemy.
male.playerX += male.playerX_change
if male.playerX <= 0:
male.playerX = 0
elif male.playerX >= 736:
male.playerX = 736
# boundry algorithm, make sure alien doesn't go out of bountry
for i in range(ufo.amount_aliens):
ufo.alienX[i] += ufo.alienX_change[i]
if ufo.alienX[i] <= 0:
ufo.alienX_change[i] = 4
ufo.alienY[i] += ufo.alienY_change[i]
elif ufo.alienX[i] >= 736:
ufo.alienX_change[i] = -4
ufo.alienY[i] += ufo.alienY_change[i]
# collision
collision = hascollision(ufo.alienX[i], ufo.alienY[i], lasr.laserX, lasr.laserY)
if collision:
lasr.laserY = 650
lasr.laser_state = "ready"
score += 5
print(score)
alienX[i] = random.randint(0, 735)
alienY[i] = random.randint(50, 200)
alien(ufo.alienX[i], ufo.alienY[i], i)
# movement of laser shot
if lasr.laserY <= 0:
lasr.laserY = 650
lasr.laser_state = "ready"
if lasr.laser_state is "fire":
fire_laser(lasr.laserX, lasr.laserY)
lasr.laserY -= lasr.laserY_change
# updates screen to show screen
main_player(male.playerX, male.playerY)
pygame.display.update()
pygame.quit()
This is the output of the error given by visual studio code (it is on line 39)
for i in range(ufo.amount_aliens):
NameError: name 'ufo' is not defined
The alien class is a bit mixed up. (Although it's hard to tell if this is just an indentation issue in the SO paste.) I'm going to assume that the list of ufos needs to be made outside the class, because this is the only thing that makes sense. Later on in the code, you declare an alien function which will occlude the alien class too. You will need to fix this first - it's best moved into the alien class as alien.draw()
So to make a bunch of aliens, create a list:
alien_image = pygame.image.load('alien.png')
all_ufos = []
for i in range( amount_aliens ):
x_pos = random.randint( 0, 735 )
y_pos = random.randint( 50, 200 )
x_speed = 3
y_speed = 7
all_ufos.append( alien( alien_image, x_pos, y_pos, x_speed, y_speed ) )
Remove the amount_aliens from the alien object, so that it now only represents a single alien.
class alien( object ):
def __init__( self, alienimage, alienX, alienY, alienX_change, alienY_change ):
self.alienimage = alienimage
self.alienX = alienX
self.alienY = alienY
self.alienX_change = alienX_change
self.alienY_change = alienY_change
And move the support functions into the alien class.
def draw( self, screen ):
""" Draw the alien to the screen """
screen.blit( self.alienimage, ( self.alienX, self.alienY ) )
def hasCollision( self, laserX, laserY ):
""" Has the laser at collided with this alien? """
distance = math.sqrt((math.pow(self.alienX - laserX, 2)) + (math.pow(self.alienY - laserY, 2)))
return ( distance < 27 ):
This allows your main loop to iterate over the list of aliens, doing stuff simply:
### Main Loop
while not exiting:
...
# paint all UFO sprites
for ufo in all_ufos:
ufo.draw( screen )
# check all lasers for collision
for laser in all_lasers:
for ufo in all_ufos:
if ( ufo.hasCollision( laser.laserX, laser.laserY ) ):
print( "*boom*" )
What you are doing here is re-creating some of the functionality of the PyGame Sprite and SpriteGroup Classes. It might be worth a quick read of the documentation on it.
I'm new to Pygame and I'm trying to move my sprite on my background image.
My sprite is not re appearing after it moves? Any ideas?
This is most of the program without some screens.
I have been trying to get this to work for many hours,
#dependencies
import pygame as P
import random as R
def welcome(screen):
#load background
bg = P.image.load("space-wallpaper.jpg")
screen.blit(bg,[0,0])
#set fonts etc
font = P.font.Font("Space_Age.ttf",60)
width, height = screen.get_size()
#play button
message = "PLAY "
text = font.render(message,1,[255 , 0, 0])
rect = text.get_rect()
x, y = text.get_size()
rect = rect.move((width - x)/2, (height - y)/2)
screen.blit(text,rect)
#high_score button
message = "HIGH SCORE "
text = font.render(message,1,[255 , 0, 0])
rect = text.get_rect()
x, y = text.get_size()
rect = rect.move((width - x)/2, (height - y)/2 +100)
screen.blit(text,rect)
def play_button(screen):
"""launch welcome screen.
"""
#welcome screen play button
font = P.font.Font("Space_Age.ttf",60)
message = "PLAY "
play_x,play_y = font.size(message)
play_text = font.render(message,1,[255 , 0, 0])
width, height = 800,600
screen.blit(play_text,[(width - play_x)/2, (height - play_y)/2])
play_rect = play_text.get_rect().move((width - play_x)/2, (height - play_y)/2)
P.display.flip()
return(play_rect)
def welcome_background(screen):
# Welcome screen background
bg = P.image.load("space-wallpaper.jpg")
screen.blit(bg,[0,0])
P.display.update()
def high_score_screen(screen):
"""opens the highscore screen"""
high_score_bg = P.image.load("bg_game.jpg")
screen.blit(high_score_bg,[0,0])
P.display.update()
def splash_screen(screen):
"""loads the first screen in the game with a 3 sec wait"""
splash_image = P.image.load('splash.jpg')
screen.blit(splash_image,[0,0])
P.display.update()
P.time.wait(2001)
def play_game(screen):
"""loads the play game screen"""
game_bg = P.image.load("bg_game.jpg")
screen.blit(game_bg,[0,0])
P.display.update()
def move_right(screen,x_cord,flagship):
dist = 20
play_game(screen)
x_cord = x_cord + dist
print(x_cord)
screen.blit(flagship,[x_cord])
P.display.update()
def key_detection(screen,flagship,x_cord):
key = P.key.get_pressed()
if key[P.K_RIGHT]:
move_right(screen,x_cord,flagship)
#move_right()
elif key[P.K_LEFT]:
print("left")
class Sprite():
def __init__(self,screen):
""" The constructor of the class """
self.flagship = P.image.load("sprite2.png")
self.x = 0
self.y = 0
def display(self,screen):
#screen.blit(self.sprite,[self.x,self.y]) changed by geoff
screen.blit(self.flagship,[self.x,self.y])
P.display.update()
_init_
# dependencies
from mods import *
import pygame as P
#initialise pygame
P.init()
def main():
# parameters to control pygame basics
screen_size = width, height = 800,600 #sixe of playing screen
P.display.set_caption('Space Smasher!')
screen = P.display.set_mode(screen_size)
clock = P.time.Clock() # timer used to control rate of looping
loop_rate = 20 #number of times per second does loop
play = True #control the playing of the actual game
splash_screen(screen)
welcome(screen)
P.display.flip()
rect_play = play_button(screen)
flagship = Sprite(screen)
while play:
key_detection(screen,flagship.image,flagship.x)
# for event in P.event.poll(): changed by geoff
event = P.event.poll() #did the player do something?
if event.type == P.QUIT:
play = False
if event.type == P.MOUSEBUTTONDOWN:
player_position = P.mouse.get_pos()
if rect_play.collidepoint(player_position):
play_game(screen)
flagship.display(screen)
P.quit()
if __name__ == '__main__':
main()
You are not calling either of your functions or your classes anywhere. You need a while loop that is similarly structured to this:
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
#Do your movements
With the following imports at the top:
import pygame, sys
from pygame.locals import *
Here is an example of moving an object with the keys:
import pygame, sys
from pygame.locals import *
pygame.init()
WIDTH=1439
HEIGHT=791
DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Hello Pygame World!')
pygame.key.set_repeat(1, 10)
circx, circy = 200, 150
CIRWIDTH=20
while True: # main game loop
if pygame.key.get_pressed()[pygame.K_UP]:
circy-=5
if pygame.key.get_pressed()[pygame.K_DOWN]:
circy+=5
if pygame.key.get_pressed()[pygame.K_RIGHT]:
circx+=5
if pygame.key.get_pressed()[pygame.K_LEFT]:
circx-=5
try:
for event in pygame.event.get():
if event.type == QUIT or event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
pygame.quit()
sys.exit()
except AttributeError:
pass
DISPLAYSURF.fill((0, 0, 0))
pygame.draw.circle(DISPLAYSURF, (158, 219, 222), (circx, circy), CIRWIDTH)
pygame.display.flip()
Main loop should be similar to:
while True:
# events - check keyboad and mouse and change player direction or speed
# move - move sprite with speed and direction
# check collison
# draw background, all objects and all sprites
# clock - to keep constant speed - FPS (Frames Per Seconds)
So you have to move sprites in every loop and draw them.
So I'm really new to programming and I'm working on a game that is sort of like Cookie Clicker, but with a twist (Mining). It is made in python/pygame. Anyways I have an image of a boulder and I want to add a rock to my inventory in the game every time i click on it.
Someone helped me out setting up the point_collide in my class. I will confess and say I don't fully understand how it works but its supposed to detect if my mouse is on a non-transparent part of my rock image.
I want the game to only give you a rock if your clicking on the NON-transparent parts of the boulder image I have blitted to the middle of the screen.
Short Question: How can I setup the game to register clicks only on my masked image?
PS: I know it'd be better to learn the fundamentals of programming first, but I have learned so much just by diving straight into a project (it keeps me going and alot more fun then reading a book).
Link to code: https://www.refheap.com/88634
The Code:
import pygame, sys
from pygame.locals import *
from datetime import datetime
if (__name__ == "__main__"):
pygame.init()
pygame.font.init()
pygame.display.set_caption("Miner Click")
clock = pygame.time.Clock()
screen = pygame.display.set_mode((960,600))
width = 960
height = 600
GREEN = (0,255,0)
RED = (255,0,0)
BLUE = (0,0,255)
BLACK = (0,0,0)
WHITE = (255,255,255)
BROWN = (84,27,1)
GREY = (198,198,198)
greenbg = pygame.image.load("greenbg.jpg").convert()
rockbutton = pygame.image.load("rockbutton.png").convert_alpha()
woodbutton = pygame.image.load("woodbutton.png").convert_alpha()
pygame.mouse.set_visible(True)
pick = pygame.image.load("pick.png").convert_alpha()
axe = pygame.image.load("axesmall.png").convert_alpha()
rockwidth = 544
rockheight = 274
clicks = 0
wood = 0
stonefont = pygame.font.SysFont("verdana", 29, True)
woodfont = pygame.font.SysFont("verdana", 29, True)
clicktext = stonefont.render('Rock: ' +str(clicks), 2, (GREY))
woodtext = woodfont.render('Wood: ' +str(wood), 2, (BROWN))
boxsize = clicktext.get_rect()
RocksX = 125
WoodX = 113
class Rock(pygame.sprite.Sprite):
def __init__(self, color = BLUE, width = 544, height = 274):
super(Rock, self ).__init__()
self.image = pygame.Surface((width, height))
self.set_properties()
self.image.fill(color)
def set_properties(self):
self.rect = self.image.get_rect()
self.origin_x = self.rect.centerx
self.origin_y = self.rect.centery
def set_position(self, x, y):
self.rect.x = 250
self.rect.y = 230
def set_image(self, filename = None):
if (filename != None):
self.image = pygame.image.load(filename).convert_alpha()
def point_collide(self, point):
x, y = point
x -= self.rect.x
y -= self.rect.y
try:
return self.mask.get_at((x,y))
except IndexError:
return False
#below is my clueless attempt at getting it to work
def checkForCursorPressed(x,y):
if pygame.mouse.get_pressed() and pygame.mouse.get_pos() == (x,y):
clicks+=1
coordfont = pygame.font.SysFont("verdana", 12, True)
rock_group = pygame.sprite.Group()
rock = Rock()
rock.set_image("rock.png")
rock.set_position(width/2, height/2)
rock_group.add(rock)
while True:
clock.tick(60)
screen.fill((255,255,255))
screen.blit(greenbg, (0,0))
x,y = pygame.mouse.get_pos()
coords = x,y
now = datetime.now()
date = '%s/%s/%s' % (now.month, now.day, now.year)
label = coordfont.render("Coordinates: "+str(coords), 1, (GREY))
date = coordfont.render("Date: "+str(date), 1, (GREY))
screen.blit(date, (650,10))
screen.blit(label, (790, 10))
screen.blit(rockbutton, (25,25))
screen.blit(woodbutton, (25,100))
clicktext = stonefont.render(' ' +str(clicks), 2, (GREY))
woodtext = woodfont.render(' ' +str(wood), 2, (BROWN))
screen.blit(clicktext, [RocksX,38])
screen.blit(woodtext, [139,WoodX])
rock_group.draw(screen)
screen.blit(pick, (x-10,y-50))
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == KEYDOWN and event.key == K_ESCAPE:
sys.exit()
pygame.display.update()
#in case i need the below again
#if x>249 and x<(795) and y>210 and y<(484):
Clicking will create a MOUSEBUTTONDOWN event, so you should be able to deal with clicks within your event-processing loop, e.g.:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == KEYDOWN and event.key == K_ESCAPE:
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
click_position = event.pos
if rock.point_collide(click_position):
print('Clicked within the rock')
clicks += 1
# Any other events that have to happen
# when the rock is clicked
I also don't understand how point_collide() works and I get an AttributeError: 'Rock' does not have attribute 'mask'.
So I would use an other possibility to detect if one clicked on non-transparent parts of the image, using colorkey.
The colorkey defines the transparent color when blitting. In my case it's white:
def set_image(self, filename = None):
...
#sets colorkey to white, depends on the image
self.image.set_colorkey((255,255,255))
New version of point_collide():
def point_collide(self, point):
x, y = point
x -= self.rect.x
y -= self.rect.y
#detects if click hits the image
if 0 <= x < self.image.get_width():
if 0 <= y < self.image.get_height():
#detects if color at clicking position != colorkey-color(transparent)
if self.image.get_at((x,y))[0:3] != self.image.get_colorkey()[0:3]:
return True
return False
How to get mouse events has been answered yet.
Ok I got it working :)
If anyone else is trying to do something similar I'll explain here.
Put the below in your code (this solves the problem 'Rock has no attribute mask' error I got)
self.mask = pygame.mask.from_surface(self.image)
Here is where I put it in my code (in my set_image def)
def set_image(self, filename = None):
if (filename != None):
self.image = pygame.image.load(filename).convert_alpha()
self.mask = pygame.mask.from_surface(self.image)
Now combine this code with Marius and it works perfectly!