Python Pygame deliver parameter when use call by sharing - python

I am the first time use call by sharing, search the result but there's no answer
i want to deliver the parameter into call by sharing
here's my codes:
#!/usr/bin/python
import sys,os
import pygame
class Setting():
'''how to deliver self.w and self.h into pic'''
pic = pygame.transform.smoothscale(pygame.image.load("pic.png"),(self.w,self.h)) #how to deliver self.w and self.h in here?
def __init__(self,width,height):
self.w=width
self.h=height
self.flag=pygame.RESIZABLE
self.screen=pygame.display.set_mode((self.w,self.h),self.flag)
self.screen_rect=self.screen.get_rect()
self.bkg=Setting.pic.convert()
pygame.display.set_caption("Muhaha")
def game():
pygame.init()
setting=Setting(1200,800)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
setting.screen.blit(setting.bkg,(0,0))
pygame.display.flip()
game()

Class-level variables are evaluated when the class is created, i.e. BEFORE the game() function is started.
You should either make pic a regular instance member (i.e. using self.pic) or you should pre-initialize it to None and only really initialize it lazily when calling the constructor the first time
class Setting:
pic = None
def __init__(self, width, height):
if Setting.pic is None:
# This code will execute only once
Setting.pic = ...
...

Related

Why do I get "missing 1 required positional argument: 'self'"?

When I use in the program querauto_group.add(QuerWagen.create_querauto()) then I get the report
missing 1 required positional argument: 'self'. When I use querauto_group.add(player.create_querauto()) then the program works.
import pygame, sys
import random
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
def create_querauto(self):
ii=random.randrange(0,8)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,25))
return QuerWagen(200,300,img)
class QuerWagen(pygame.sprite.Sprite):
def __init__(self, pos_x,pos_y,img):
super().__init__()
self.image=img
self.rect = self.image.get_rect(center = (pos_x,pos_y))
def update(self):
self.rect.x+=5
if self.rect.x > screen_width + 200:
self.kill()
def create_querauto(self):
ii=random.randrange(0,8)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,25))
return QuerWagen(200,300,img)
pygame.init()
clock = pygame.time.Clock()
screen_width,screen_hight = (1200,800)
screen = pygame.display.set_mode((screen_width,screen_hight))
player = Player()
querauto_group = pygame.sprite.Group()
WECHSELBILD = pygame.USEREVENT + 1
pygame.time.set_timer(WECHSELBILD,1800)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type ==WECHSELBILD:
#querauto_group.add(QuerWagen.create_querauto())
querauto_group.add(player.create_querauto())
screen.fill((30,30,30))
querauto_group.draw(screen)
querauto_group.update()
pygame.display.flip()
clock.tick(30)
pygame.quit()
quit()
On both classes create_querauto is an instance method, meaning that the class needs to be instantiated in order to call the method.
That's why it is working with the player instance.
i.e.
class Player:
def create_querauto(self):
ii=random.randrange(0,8)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,25))
return QuerWagen(200,300,img)
player_instance = Player()
player_instance.create_querauto() # This will work
Player.create_querauto() # This will throw the error you see above
If you would like to method to work without instantiating the class first you can define it as a static method, using the #staticmethod decorator
This would look like:
class QuerWagen(pygame.sprite.Sprite):
#staticmethod
def create_querauto():
ii=random.randrange(0,8)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,25))
return QuerWagen(200,300,img)
Now you can call that function on the class directly like you were trying to do.
querwagen = QuerWagen.create_querauto() # works fine

python pygame load image to Initialize screen very slowly

I write a script to implementate the continuous rains,the function is totally correct.
Only one issue is when i run the script is it really slow to initialize screen, it almost takes 6-8 seconds then i can see the image on the screen.
i search some reasons for why cause this issue such as useconvert_alpha() to load the image, but nothing changed, it is still very slowly
So what caused this issue???
here's the code:
#!/usr/bin/python
import sys
import pygame as p
from random import randint
#13-4
class Setting():
def __init__(self,width,height):
self.w=width
self.h=height
self.screen=p.display.set_mode((self.w,self.h),p.RESIZABLE,0)
self.speed = 1 #rain speed
p.display.set_caption("EXE 13-4")
class Rain(p.sprite.Sprite):
def __init__(self):
super().__init__()
pic=p.image.load("../image/rain.jpg").convert_alpha()
self.image=p.transform.smoothscale(pic,(100,100))
self.rect=self.image.get_rect()
self.rect.x=(self.rect.width)/2
self.y=float(self.rect.y) # store the rain rect in temp y
def create(self,setting,rains):
spacex=setting.w-2*self.rect.x #calculate the space to put the rain
numbers=int(spacex/(2*self.rect.x)) #calculate the numbera of every column
rows=int(setting.h/(self.rect.height)) #calculate the rows
for row in range(rows):
for number in range(numbers): #store the whole rain into Group rains
rain=Rain()
rain.number=number
rain.row=row
rain.rect.x =rain.rect.x+rain.rect.width*number
rain.y = rain.rect.y+2*rain.rect.height*row
rain.rect.y =rain.y
rains.add(rain)
def check_edge(setting,rains):
for rain in rains.sprites(): #if any rain reach the bottom of screen restart them to the top
if rain.rect.y == setting.h:
rain.y=0
rain.rect.y=rain.y
def update(self,setting):
self.y += setting.speed
self.rect.y= self.y
def blit(setting,rains):
rains.update(setting)
rains.draw(setting.screen)
def game():
p.init()
setting=Setting(1200,800)
rain=Rain()
rains=p.sprite.Group()
rain.create(setting,rains)
while True:
for event in p.event.get():
if event.type == p.QUIT:
sys.exit()
elif event.type == p.KEYDOWN:
if event.key == p.K_ESCAPE:
sys.exit()
setting.screen.fill((0,0,255))
Rain.check_edge(setting,rains)
Rain.blit(setting,rains)
p.display.flip()
game()
What you actually do is to load the same image again and again for each instance of Rain.
Load the image once and use the same image for all the raindrops. e.g. use a class attributes for the raindrop image (Rain.raindrop_pic). Furthermore, avoid to do convert_alpha() and transform.smoothscale multiple times:
class Rain(p.sprite.Sprite):
raindrop_pic = p.transform.smoothscale(
p.image.load("../image/rain.jpg").convert_alpha(), (100,100))
def __init__(self):
super().__init__()
self.image = Rain.raindrop_pic
# [...]

Pygame Menu: calling another .py file

I'm learning pygame by helping a friend make a Menu for his interactive TicTacToe game. It's simple enough, a title and 2 buttons for starting and exiting the game. He has the game done, I just need to link my menu to his game.
After fiddling with pygame, I finally finished making the images appear in the pygame window(I never thought that seeing text appear in a blank window for the first time could look so beautiful! T^T). I believe that the next step is to make the images act like buttons to call another python file.
Here is my simple code for the menu:
import pygame
from pygame.locals import *
from sys import exit
pygame.init()
resX, resY = 640, 480
windowObj = pygame.display.set_mode((resX,resY))
titleImg = pygame.image.load("title.png")
startImg = pygame.image.load("start.png")
exitImg = pygame.image.load("exit.png")
def width_center(img):
"""For horizontally setting an image."""
return resX/2 - x(img)/2
def height_center(img):
"""For vertically setting an image."""
return resY/2 - y(img)/2
def x(img):
"""Width of object."""
return img.get_width()
def y(img):
"""Height of object."""
return img.get_height()
while True:
pygame.display.update()
windowObj.fill((255,255,255))
windowObj.blit(titleImg,(width_center(titleImg), 30))
#This I want to link:
windowObj.blit(startImg,(width_center(startImg),height_center(startImg)-10))
windowObj.blit(exitImg,(width_center(exitImg),height_center(exitImg)+y(startImg)))
for i in pygame.event.get():
if i.type == QUIT:
exit()
Simply put, I want to know how to make the startImg call TTTClick.py. Should there also be a certain format for his TTTClick.py?
Thanks :)
If it's one project, you can have 'title screen' state, and 'game' states.
Psuedo code:
class Game():
def __init__(self):
self.done = False
self.state = "title"
def game_draw(self):
# game draw
def game_update(self):
# game event handling, and physics
def title_draw(self):
# title draw
def title_update(self):
# on event click
self.state = "game"
def loop(self):
# main loop
while not self.done:
if state == 'title':
title_update()
title_draw()
elif state == 'game':
game_update()
game_draw()
if __name__ == "__main__":
game = Game()
game.loop()
Note: x, height_center ect. already exist in pygame.Rect
# if Surface
titleImage.get_rect().width
# if Sprite
titleImage.rect.width
There's more, rect.center, rect.centerx, see the full listing at http://www.pygame.org/docs/ref/rect.html

How do you call an instance method from Class "B" from within Class "A"?

I'm not sure if I'm using classes correctly. I'm attempting to build a simple menu using pygame. This is my first foray into gui stuff. I have no idea how to structure my code.
I found that I could make a general Button class to handle all of the mouse over/mouse click stuff, and then I can subclass that for each button, and override the do_action method to give each button a specific action.
class Button(pygame.sprite.Sprite):
global screen_flags
def __init__(self, images, pos):
pygame.sprite.Sprite.__init__(self)
self.images = images
self.image = images[0]
self.rect = self.image.get_rect()
self.rect.move_ip(pos)
def update(self, events, surface):
# if not screen_flags['config']:
for event in events:
if event.type == MOUSEMOTION:
if self.rect.collidepoint(event.pos):
self.image = self.images[1]
else:
self.image = self.images[0]
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1 and self.rect.collidepoint(event.pos):
self.image = self.images[-1]
screen_flags['config'] = 1
self.do_action()
self.set_flag()
elif event.type == MOUSEBUTTONUP:
self.image = self.images[0]
screen.blit(self.image, self.rect)
def do_action(self):
pass
def set_flag(self):
pass
class CheckBox(Button):
def __init__(self, images, pos):
Button.__init__(self, images, pos)
self.is_clicked = False
def update(self, events, surface):
for event in events:
if event.type == MOUSEMOTION:
if not self.is_clicked:
if self.rect.collidepoint(event.pos):
self.image = self.images[1]
else:
self.image = self.images[0]
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1 and self.rect.collidepoint(event.pos):
if not self.is_clicked:
self.image = self.images[-1]
self.is_clicked = True
else:
self.image = self.images[0]
self.is_clicked = False
screen.blit(self.image, self.rect)
class Cancel(Button):
def do_action(self):
screen_flags['config'] = 0
So, as you can see,they don't really do anything yet. I can toggle the check box on and off, and open and close one 'config' window, but that's as far as I've gotten. The rest of the code:
global count
global sTime
config_button_img = load_sliced_images(25, 25, c_buttons)
config_button = Button(config_button_img, (608,4))
input_bar = load_sliced_images(351,33, inpt_bar)
text_box = Textbox(input_bar, (144,155))
s_button = load_sliced_images(110,32, sbmt_bttn)
submit = Button(s_button, (241,301))
c_button = load_sliced_images(110,32, cncl_bttn)
cancel = Cancel(c_button, (385, 301))
c_boxes = load_sliced_images(20,19, chk_box)
check_box = CheckBox(c_boxes, (200,200))
try:
while True:
# ****************************
# Pygame section
events = pygame.event.get()
for event in events:
if event.type == QUIT:
screen_flags['alert'] = 1
ding.play(0,1000)
elif event.type == MOUSEBUTTONDOWN:
text_box.set_focus(event.button, event.pos)
screen.blit(background, (0,0))
screen.blit(client_logo, (0,30))
screen.blit(tag, (174,462))
if screen_flags['config']:
screen.blit(config_window_img, (0,0))
submit.update(events, screen)
cancel.update(events, screen)
check_box.update(events, screen)
if screen_flags['alert']:
screen.blit(alert_dialog, (0,0))
config_button.update(events, screen)
pygame.display.update()
except KeyboardInterrupt:
try:
pygame.quit()
except:
pass
So this works kind of as expected. I'm unsure where to go from here. Do I continue to wrap up logic inside of the classes? For instance, the next thing I'm attempting to do is make it so that when the "cancel" button is clicked it unchecks the check box.
I tried changing the Cancel class to do just that.
class Cancel(Button):
def do_action(self):
screen_flags['config'] = 0
check_box.is_clicked=False
However, this is giving me a GlobalName Error. How do I target an instance method from within a different class? Is this even the correct way to go about it? Or have only some logic, like the update() stuff to take care of the mouse, in then handle what the classes do by passing variables to and from the different classes fro main()? Should I have all of the classes use global variables?
Is there any good articles on gui practices. Things like how to structure code etc..?
Hopefully the above makes sense.
Personally, I would make it so that each of my classes accepted screen_flags as an argument to the constructor (__init__). Then each of your classes would have a handle on the "global" data that they need. A real easy way to do this is...
class Cancel(Button):
def __init__(self,*args,**kwargs):
self.screen_flags=kwargs.pop('screen_flags')
Button.__init__(self,*args,**kwargs) #Some might advise you to use super here...
def do_action(self):
self.screen_flags['config'] = 0
#now use the cancel class
cancel=Cancel(c_button, (385, 301),screen_flags=screen_flags)
Of course, depending on what the shared data looks like (how many different variables you have, etc), you might want to pass a dictionary, or other object to make it so you don't need to pass 5000 different pieces of shared data around.
Another way of dealing with this is to define your "global" data in a class as "class variables" and then inherit from that class.
class GlobalData(object):
stuff=None
class FooButton(Button,GlobalData):
def do_action(self):
print self.stuff
#If you do something in here, don't do: self.stuff = blah
#instead, you *should* do: GlobalData.stuff = blah
#However, it is fine to change mutable objects in place.
# e.g. self.stuff["dict_key"]=blah
#Now we can assign to GlobalData and instances of
#FooButton will see the differences immediately.
cancel=FooButton(c_button, (385, 301))
cancel.do_action()
GlobalData.stuff="Cows say Moo"
cancel.do_action()
I hope this helps. There was a lot in you post, so sorting through it all was a little difficult.
EDIT
In case you don't understand how class variables are handled, see the comments in do_action. Basically, you need to be careful that you don't lose a handle on your data...
GUI stuff can be done nicer.
Yes, do wrap your control in classes.
I'd recommend to try this.
First, define logical interface for your controls. Forget about implementation details for a minute. Any control can be clicked; define method onClick(pos). Check boxes can be checked or unchecked; define setChecked(bool). Windows can be shown or hidden, define setVisible(bool), etc.
Create a common ancestor for clickable controls. Within its event handler, call onClick(event.pos). The default implementation would do nothing. Now you can call onClick() of a control when you want to imitate a click. You will want onMouseDown and onMouseUp to do things like click animation, onMouseIn and onMouseOut for hover events, etc. The only place where you'll care about the gory details of event dispatch will be your common ancestor.
Don't refer directly to global state; it leads to all sorts of unpleasant things. Instead, let every control know its state and how to change it (we're doing OOP anyway). So, the check box gets a isChecked() method, etc.
Now Cancel button would only have to override its onClick method and constructor. In constructor, pass the CheckBox instance; in cancel_button.onClick just call Button.onClick and then self.check_box.setChecked(False).

pygame code organization

I've started to learn making games with python/pygame and as though it is easy to make a working game quickly in pygame, there's no real tutorial on how to organize the code in a sensible way.
On the pygame tutorials page, I've found 3 ways to do it.
1- No use of classes, for small projects
2- MVC ruby-on-rails kind of structure but without the rails framework which results in something overly complicated and obscure (even with OO programming and rails knowledge)
3- C++-like structure as follows: (clean and intuitive but maybe not very much python-like?)
import pygame
from pygame.locals import *
class MyGame:
def __init__(self):
self._running = True
self._surf_display = None
self.size = self.width, self.height = 150, 150
def on_init(self):
pygame.init()
self._display_surf = pygame.display.set_mode(self.size)
pygame.display.set_caption('MyGame')
#some more actions
pygame.display.flip()
self._running = True
def on_event(self, event):
if event.type == pygame.QUIT:
self._running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
self._running = False
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
print event.pos
def on_loop(self):
pass
def on_render(self):
pass
def on_cleanup(self):
pygame.quit()
def on_execute(self):
if self.on_init() == False:
self._running = False
while( self._running ):
for event in pygame.event.get():
self.on_event(event)
self.on_loop()
self.on_render()
self.on_cleanup()
if __name__ == "__main__" :
mygame = MyGame()
mygame.on_execute()
I'm used to make SDL games in C++ and I use this exact structure but I'm wondering if it's usable for both small and large projects or if there's a cleaner way in pygame.
For example I found a game organized like this:
imports
def functionx
def functiony
class MyGameObject:
class AnotherObject:
class Game: #pygame init, event handler, win, lose...etc
while True: #event loop
display update
It also looks very well organized and easy to follow.
Which structure should I use consistently in all my projects so as to have a clean code usable in small and large games?
I'd also suggest maybe using comments (as dreary as it seems as first) for dividing your work. As an example:
import pygame, random, math
## CLASSES ----------------------------------------------
class Ball():
def __init__(self, (x,y), size):
"""Setting up the new instance"""
self.x = x
self.y = y
self.size = size
## FUNCTIONS --------------------------------------------
def addVectors((angle1, length1), (angle2, length2)):
"""Take two vectors and find the resultant"""
x = math.sin(angle1) * length1 + math.sin(angle2) * length2
y = math.cos(angle1) * length1 + math.cos(angle2) * length2
## INIT -------------------------------------------------
width = 600
height = 400
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("S-kuru")
And so on.
As another option to consider, have you thought about using sub-modules? They're just other Python files (.py) where you place commonly-used functions.
def showText(passedVariable):
print passedVariable
return
This new file is the imported, just as math or random would be and the function used as such:
import mySubModule
mySubModule.showText("Hello!")
But that's just how I work. Absolutely follow what you can understand, not just now but next week or year also.
Do what you can follow. If you can make sense of the code you posted, then that's what you should use. If a different structure feels more natural, use that instead.

Categories