Variable Won't Update In Class - python

import sys
import pygame
from pygame.locals import *
pygame.init()
class Game:
def __init__(self):
self.width = 800
self.height = 900
self.win = pygame.display.set_mode([self.width, self.height])
self.caption = pygame.display.set_caption('Clicker Game','Game')
self.money = 0
self.moneyperclick = 0
def moneytracker(self):
self.money = self.money + self.moneyperclick
print(self.money)
def mousestuff(self):
self.mousepos = pygame.mouse.get_pos()
self.clicked = pygame.mouse.get_pressed()
def mainloop(self):
self.mousestuff()
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
self.moneytracker()
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
while True:
Game().mainloop()
I'm still somewhat new to coding but I am very confused as to why the self.money variable isn't updating even though I call for it to update. I've done some tests and I know that it is looping the code where I set self.money = 0 but I don't know how to get around this. Thanks

It looks like the problem is here:
while True:
Game().mainloop()
This creates a new Game object in every iteration of the loop, which means all the values are initialized for the first time, because it's a new object.
Alternatives are to move the while True loop inside mainloop(), or try something like:
game = Game()
while True:
game.mainloop()
This creates a single Game object as game, whose mainloop() method is called repeatedly. Because the object is only created once, the attributes of the object (e.g. money, accessed as self.money) that are modified as a result of player actions will keep their values between iterations of the loop.
In the original loop structure, a new Game object was created each time, which means that a player's actions were only performed once before the object was abandoned and replaced by a new one, with newly initialized attributes.

Related

Timer doesnt go lower?

I'm creating a Snake game. When I lower the cooldown of the Timer I want the snake to move faster.
It's actually working, but only if I change the number of the game speed before starting the project. If I start the project and change the timer in game, by a function, then var for the timer gets lower (printed it in different situations) but the speed doesn't change.
game_speed = 100
SCRREEN_UPDATE = pygame.USEREVENT
pygame.time.set_timer(SCRREEN_UPDATE, game_speed)
while go:
events = pygame.event.get()
if not game_over:
screen.fill((0,90,10))
snake.draw_grass()
for event in events:
main_game.Quit(event)
if event.type == SCRREEN_UPDATE:
main_game.update()
self.list.append(self.user_input)
self.user_input = int(self.user_input)
if isinstance(self.user_input,str):
self.list = [0]
self.user_input = "0"
game_speed -= int(self.list[-1])
self.list = [0]
self.user_input = "0"
print(game_speed)
return game_speed
The timer event and the game_speed variable are not tied. The timer interval doesn't magically change when you change the value of game_speed. You have to restart the timer with the new interval. So after changing game_speed, pygame.time.set_timer needs to be called again:
game_speed -= int(self.list[-1])
pygame.time.set_timer(SCRREEN_UPDATE, game_speed)

How do I use the clock/ticks function in Pygame to spawn another object after a certain amount of time?

class Sideways:
"""Overall class to manage game assets"""
def __init__(self):
"""Initialize the game and create game resources"""
pygame.init()
self.screen = pygame.display.set_mode((1200, 600))
self.screen_rect = self.screen.get_rect()
pygame.display.set_caption("Pew Pew")
self.bg_color = (204, 255, 255)
self.ship = Ship(self)
self.moving_up = False
self.moving_down = False
self.moving_left = False
self.moving_right = False
self.bullets = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
FIRE_EVENT = pygame.USEREVENT + 1 # This is just a integer.
pygame.time.set_timer(FIRE_EVENT, 1000) # 1000 milliseconds is 1 seconds.
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == FIRE_EVENT: # Will appear once every second.
self._create_fleet()
I'm trying to spawn another ship in pygame after a certain interval of time.
I just learned about the clock/ticks function from my previous question being directed to another thread that showed me it. Thank you. I tried to incorporate that into my code during this section.
However, when I run it, the game freezes up and crashes as if it's spawning too many things at the same time to handle and overloads. How would I manage to use this function correctly?
You must create the objects in the application loop, but not in a separate loop. This extra loop freezes your system. In general, if you want to control something over time in pygame, you have two options:
Use pygame.time.get_ticks() to measure time and and implement logic that controls the object depending on the time.
Use the timer event. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue. Change object states when the event occurs.
For example see Spawning multiple instances of the same object concurrently in python or create clock and do action at intervals and many more similar answers.

Pygame splash screen crashes game

This has been edited, the original post was about blitting the splash screens
I'm working on a simple game using pygame, the game is almost complete however i'm having some issues with the splash screen. The current issue is that when the game is run, the splash screens blit like they are supposed to, however if the user clicks anywhere on the screen or tries to exit the game, it crashes. Does anybody know a way around this issue, what i am hoping for is that the user would even be able to exit the game or even skip the splash screen whilst they are being displayed.
def main():
'''Here the game is being initialised'''
pygame.init() #Initialising Pygame
pygame.key.set_repeat(1, 20) #Registers event every 20MS if a key is held down
countFont = pygame.font.Font(None,18) #Font being set
statusFont = pygame.font.Font(None,18) #Font being set
screen = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
pygame.display.set_caption('Do Not Get Capped')
#Drawable surface
background = pygame.Surface(screen.get_size())
#Used for converting color maps
background = background.convert()
#Splashscreen
#image fades in
for i in range (225):
background.fill((0,0,0))
image = pygame.image.load("splash_screen1.png")
image.set_alpha(i)
logoimage = screen.blit(image,(0,0))
pygame.display.flip()
pygame.time.delay(2000)
for i in range (225):
background.fill((0,0,0))
image = pygame.image.load("splash_screen2.png")
image.set_alpha(i)
logoimage = screen.blit(image,(0,0))
pygame.display.flip()
pygame.time.delay(4000)
'''The main function which is called at the end of this code'''
class Game():
'''This class's purpose is to keep track of the current score'''
def __init__(self):
self.score=0
self.goalNumbers=0
class Gun(pygame.sprite.Sprite):
'''This is the gun that the user controls'''
def __init__(self):
'''This is the class contructor'''
pygame.sprite.Sprite.__init__(self)
self.image=pygame.image.load("turret.png") #Loading the gun's image
self.rect = self.image.get_rect() #Getting the image's Rect
self.rect.x = 240 #Setting the rect's X position
self.rect.y = 630 #Setting the rect's Y position
def moveGun(self,orientation):
'''This function allows the gun to move on the screen.
If the orientation is facing left and the gun is 5 pixels
away from the wall, the gun is moved left & vice-a-versa'''
if orientation=="left" and self.rect.x>5:
self.rect.x-=5
if orientation=="right" and self.rect.x<(480-self.rect.width):
self.rect.x+=5
class Projectile(pygame.sprite.Sprite):
'''This class sets up the projectile/bullets that are controlled
by the user'''
def __init__(self,gun):
pygame.sprite.Sprite.__init__(self)
self.image=pygame.image.load("bullet.png")
self.rect=self.image.get_rect()
'''The code below places the projectile on top of the gun'''
self.rect.x=gun.rect.x+(gun.rect.width/2)-(self.rect.width/2)
self.rect.y=gun.rect.y-gun.rect.height
def updateProjectile(self):
'''This checks if the projectile has reached the top of the screen
if it hasn't it will continue to move up. If it has it will be deleted'''
if self.rect.y>0-self.rect.height:
self.rect.y-=5
else:
self.kill()
class Objects(pygame.sprite.Sprite):
'''This class creates the objects, they are loaded from the computer
and assigned to variables'''
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.obj=random.randint(1,3)
if self.obj==1: imagefile="capped"
if self.obj==2: imagefile="notcapped1"
if self.obj==3: imagefile="notcapped2"
self.image=pygame.image.load(imagefile+".png")
self.rect=self.image.get_rect()
self.rect.y=-0-self.rect.height
self.rect.x=(random.randint(2,44)*10)
def updateProjectile(self,game):
'''This function allows for the objects to move down the screen'''
if self.rect.y<640:
self.rect.y+=7 #This controls the amount of pixels the objects move down thus contrlling the speed
else:
if self.obj==1:
'''Here the code is tracking the users score'''
game.score+=10 #This adds 10 to the game's score
game.goalNumbers+=1
else:
game.score-=50
self.kill()
def shot(self,game):
'''This function updates the score as well as removing the objects when they are hit by a projectile'''
if self.obj == 1:
game.score-=50
else:
game.score+=10
self.kill()
# Create initial object instances
'''Here i am creating objects based on the classes i created'''
game=Game()
gun=Gun()
sprites=pygame.sprite.Group()
sprites.add(gun)
obstacles=pygame.sprite.Group()
projectiles=pygame.sprite.Group()
'''This variable will be used to control when to come out of the loop, i will state when this happens belows'''
finish=False
clock=pygame.time.Clock() #Initialising the clock
tick=0
'''This is the start of the main while loop, this loop will continue
until the variable 'finish' becomes false'''
while finish == False:
clock.tick(30) #Loop will run 30 times a second
tick+=1
screen.fill(bColour)
'''Here the main events are being run'''
for event in pygame.event.get():
if event.type==pygame.QUIT:
'''If the user clicks the exit button, the finish variable is made True,
this means that rather than exiting the game, the user's score is displayed after
which the game closes'''
finish = True
if event.type==pygame.KEYDOWN:
'''Here the script is checking for KEYDOWN events, these are events triggered
when the user presses on a keyboard key. In this case events are triggered when the left, right
and space keys are pressed.'''
if event.key==pygame.K_LEFT:
gun.moveGun("left") #If this is activated the 'orientation' changes to 'left' which shunts the gun 5 pixels to the left
if event.key==pygame.K_RIGHT:
gun.moveGun("right") #'Orientation' changes to 'right' which shunts the gun 5 pixels to the right
if event.key==pygame.K_SPACE:
'''This triggers the projectiles function'''
projectile=Projectile(gun)
projectiles.add(projectile)
'''This controls the projectiles and objects moving around the window'''
for projectile in projectiles:
projectile.updateProjectile()
for obstacle in obstacles:
obstacle.updateProjectile(game)
if tick>60:
'''This controls at what rate the objects fall which is now once every two
seconds, this is because the loop runs in 30 second intervals and the
clock is ticking at 60 seconds'''
if len(obstacles)<10:
obstacle=Objects()
obstacles.add(obstacle)
tick=0
collisions=pygame.sprite.groupcollide(obstacles,projectiles,False,True)
'''Here the script is checking whether the objects are hit by a projectile
if they are, the 'shot' function is triggered'''
if collisions:
for obstacle in collisions:
obstacle.shot(game)
'''This block of code constantly updates the player's scores'''
scoreText=countFont.render('Your current score is:'+str(game.score),True,(255,255,255),bColour)
screen.blit(scoreText,(0,620))
statusText=statusFont.render('You have '+str(10-game.goalNumbers)+' more tries',True,(255,255,255),bColour)
screen.blit(statusText,(0,10))
'''This code below updates and blits the objects to the screen'''
sprites.draw(screen)
projectiles.draw(screen)
obstacles.draw(screen)
pygame.display.flip()
if game.goalNumbers>=10:
'''This if statement is checking whether 'obj1' has touched the floor 10 times
and if it did, the finish variable is made true thus ending the game'''
finish=True
'''This is the last piece of code visible to the user,
what happens here is that the final message showing the final score is shown'''
scoreCountHolder=pygame.image.load("scoreframe.png")
scoreCountHolder.convert_alpha()
left=90
top=250
screen.blit(scoreCountHolder,(left,top))
countFont=pygame.font.Font(None,52)
statusText=countFont.render('Your Score:'+str(game.score),True,bColour,(255,255,255))
screen.blit(statusText,(105,300))
pygame.display.flip()
while True:
'''This waits for the user to quit the game'''
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
if __name__ == '__main__':
'''The main function being called'''
main()
When you have a pygame application, you take all events from the input queue.
The operating system, adds new events onto the queue, while your application removes them.
Since you do not remove the events, the operating system thinks that your application froze.
To fix this, you should call pygame.event.pump()
From the pygame docs:
For each frame of your game, you will need to make some sort of call
to the event queue. This ensures your program can internally interact
with the rest of the operating system. If you are not using other
event functions in your game, you should call pygame.event.pump() to
allow pygame to handle internal actions.
This function is not necessary if your program is consistently
processing events on the queue through the other pygame.eventpygame
module for interacting with events and queues functions.
There are important things that must be dealt with internally in the
event queue. The main window may need to be repainted or respond to
the system. If you fail to make a call to the event queue for too
long, the system may decide your program has locked up.
What happens is that you put a frame, Pygame then expects you to take the events that happened in the mean time out of its event queue. If you don't the OS thinks, that application got stuck!
You need to handle the events while you show the splash screen, if you want to allow the user to skip the flash screen.
Here's a way around that problem, it allows you to add specific event handling for splash screen:
class SplashScreen(object):
def __init__(self):
super().__init__()
# Use numbers for ordering, make them continuous.
self.image_dict = {
1: "splash_screen1.png",
2: "splash_screen2.png",
}
# Current image we are on!
self.current_index = min(self.image_dict)
# Last image
self.end_index = max(self.image_dict)
# Minimum alpha value
self.alpha_min = 0
# Maximum alpha value
self.alpha_max = 225
# Current alpha value
self.alpha = self.alpha_min
self.show = True
# I leave it to you to figure out this function.
def get_image(self):
image_name = self.image_dict[self.current_index]
image = pygame.image.load(image_name)
image.set_alpha(self.alpha)
self.alpha += 1
if self.alpha > self.alpha_max:
self.alpha = self.alpha_min
self.current_index += 1
if self.current_index == self.end_index:
self.show = False
return image
splash_screen = SplashScreen()
while True:
# The ever-green event handling loop!
for event in pygame.event.get():
...
if splash_screen.show:
# Splash screen stuff, one frame at a time
background.fill((0, 0, 0))
img = splash_screen.get_image()
screen.blit(img, (0, 0))
else:
# Game stuff, no need to call display.flip here, called at the end.
...
# Called at the end after frame is ready!
pygame.display.flip()
Left as an exercise
You should load and add the loaded images in the image_dict in __init__. It's not a good idea to keep reloading images from disk each time you blit them.

python/pygame image cant be found the the same folder

hello im new to python/pygame and tried to make a basic project. it did not turn out as planned as i don't understand this error if you can tell my why my image is not loading it will very much appreciated. Traceback (most recent call last):
File "C:\Users\Nicolas\Desktop\template\templat.py", line 15, in <module>
screen.fill(background_colour)
NameError: name 'background_colour' is not defined
this is the error i was speaking of however i have fixed now. how ever now the screen opens displayes the background and crashes.
import pygame, sys
pygame.init()
def game():
background_colour = (255,255,255)
(width, height) = (800, 600)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Tutorial 1')
pygame.display.set_icon(pygame.image.load('baller.jpg'))
background=pygame.image.load('path.png')
target = pygame.image.load('Player.png')
targetpos =target.get_rect()
screen.blit(target,targetpos)
screen.blit(background,(0,0))
pygame.display.update()
while True:
screen.blit(background,(0,0))
screen.blit(target,targetpos)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if__name__==('__main__')
game()
You missed the __init__ definition!
While your code does run, it is not what you want. There's an infinite loop inside the definition of the class, which means, however you are running this, there's something missing. You should put this code (most of it at least) inside the __init__ function, and then create an instance of the class.
This is what I assume you want:
import pygame, sys
class game():
width, height = 600,400
def __init__(self):
ball_filename = "Ball.png"
path_filename = "path.png"
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption('Star catcher')
self.background = pygame.image.load(path_filename)
self.screen.blit(self.background,(0,0))
self.target = pygame.image.load(ball_filename)
def run(self):
while True:
self.screen.blit(self.background, (0,0))
targetpos = self.target.get_rect()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if __name__ == "__main__":
# To run this
pygame.init()
g = game()
g.run()
UPDATE:
I made more modifications than what you must do, but they could be useful. I did not test this, but it should be fine.
The error of width and height not being defined is because they are not local/global variables, but bound to the class and/or the instance of the class, therefore in their namespace. So you need to access these either via game.width (per class) or self.width (per instance, only inside a method defined in the class) or g.width (per instance, if you are outside the class definition and g is an instance of game class).
I hope I'm clear. :)

Using classes in Pygame

Okay, so I am starting to have fun with pygame. But I've got a problem. I tried to somehow enchance my code, make it organised, so I've decided to use classes here. It looks like this:
import pygame
from pygame.locals import *
import sys
pygame.init()
class MainWindow:
def __init__(self, width, height):
self.width=width
self.height=height
self.display=pygame.display.set_mode((self.width,self.height))
pygame.display.set_caption("Caption")
def background(self)
img = pygame.image.load("image.png")
self.display.blit(img, (0,0))
mainWindow = MainWindow(800,600)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.exit()
sys.exit()
mainWindow.background()
pygame.display.update()
Okay, works. But what if I want to, for example fill the windows with white color? Then I have to define a method fill(), which will just self.display.fill(), right? Is there a way, to handle it normally, without defining hundreds of pygame-already-existing methods in my class?
And one another thing. If I do something by using my class, and I screw up, I always get this msg:
File "C:/Python35/game.py", line 23, in <module>
pygame.display.update()
pygame.error
And I actually don't know what the heck is wrong. If I do this normally, without classes, then I get erros such as, pygame object blabla has no method blablabla or something like that, I just know what's happening. Is there a way to get through this, and find what's going on?
Thanks in advance for your help!
What you are doing here is on the right track, but it is done the wrong way. Your main "game loop" should be inside the class itself as a method, rather than calling stuff from outside the class in an actual loop. Here is a basic example of what you should be doing.
# Load and initialize Modules here
import pygame
pygame.init()
# Window Information
displayw = 800
displayh = 600
window = pygame.display.set_mode((displayw,displayh))
# Clock
windowclock = pygame.time.Clock()
# Load other things such as images and sound files here
image = pygame.image.load("foo.png").convert # Use convert_alpha() for images with transparency
# Main Class
class MainRun(object):
def __init__(self,displayw,displayh):
self.dw = displayw
self.dh = displayh
self.Main()
def Main(self):
#Put all variables up here
stopped = False
while stopped == False:
window.fill((255,255,255)) #Tuple for filling display... Current is white
#Event Tasking
#Add all your event tasking things here
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN:
stopped = True
#Add things like player updates here
#Also things like score updates or drawing additional items
# Remember things on top get done first so they will update in the order yours is set at
# Remember to update your clock and display at the end
pygame.display.update()
windowclock.tick(60)
# If you need to reset variables here
# This includes things like score resets
# After your main loop throw in extra things such as a main menu or a pause menu
# Make sure you throw them in your main loop somewhere where they can be activated by the user
# All player classes and object classes should be made outside of the main class and called inside the class
#The end of your code should look something like this
if __name__ == __main__:
MainRun()
The main loop will call itself when the object MainRun() is created.
If you need more examples on specific things such as object handling let me know and I will see if I can throw some more information up for you.
I hope this helps you with your programming and the best of luck to you.
========================= EDIT ================================
In this case for these special operations make them object specific. Instead of using one generic method to blit your objects, make each object have its own function. This is done this way to allow for more options with each object you make. The general idea for the code is below... I have created a simple player object here.
#Simple player object
class Player(object):
def __init__(self,x,y,image):
self.x = x
self.y = y
self.image = image
#Method to draw object
def draw(self):
window.blit(self.image,(self.x,self.y))
#Method to move object (special input of speedx and speedy)
def move(self,speedx,speedy):
self.x += speedx
self.y += speedy
Now here is how you use the object's methods... I have included an event loop to help show how to use the move function. Just add this code to your main loop wherever it is needed and you will be all set.
#Creating a player object
player = Player(0,0,playerimage)
#When you want to draw the player object use its draw() method
player.draw()
#Same for moving the player object
#I have included an event loop to show an example
#I used the arrow keys in this case
speedx = 0
speedy = 0
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
speedy = -5
speedx = 0
elif event.key == pygame.K_DOWN:
speedy = 5
speedx = 0
elif event.key == pygame.K_RIGHT:
speedy = 0
speedx = 5
elif event.key == pygame.K_LEFT:
speedy = 0
speedx = -5
elif event.type == pygame.KEYUP:
speedx = 0
speedy = 0
#Now after you event loop in your object updates section do...
player.move(speedx,speedy)
#And be sure to redraw your player
player.draw()
#The same idea goes for other objects such as obstacles or even scrolling backgrounds
Be sure to use the same display name of the display inside your draw function.

Categories

Resources