Class variables resetting in python - python

Right now I am having a problem where a class' values are being reset I am not sure where. can anyone help? Here is the code
while True:
#some code#
Hub().paint(gameDisplay)
The Hub/paint function is shown below
def paint(self, screen):
if self.gimseen == 0 and self.pressed == 0:
screen.blit(image1, (self.x, self.y))
self.pressed = (pygame.mouse.get_pressed()[0])
if self.pressed == 1:
self.gimseen += 1
in some code I call a function that i also use to get the value of self.pressed is there any other way I could do this besides adding a line above the while loop that states that hub = hub()?

The reason your variables are resetting, is because you create a brand new instance of the Hub() each time your while loop loops. This means that each time you call paint(), any state you had with the previous instance of Hub() is lost. Instead, you need to create one instance of the Hub() class outside of the while loop, and then call the method paint() inside of the loop on the one instance of Hub():
# only create one instance of hub.
hub = Hub()
# create you loop.
while True:
# call the method paint on the
# the one instance of Hub(); hub.
hub.paint()

Related

How do I assign values to a variable with a schedule function in pyglet?

With the following code
x=1.0
def update(dt):
space.step(dt)
def xprinter(self, x):
print (x)
return x+1
if __name__ == "__main__":
x=pyglet.clock.schedule(xprinter,x)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
My return is simply 1.0 over and over. I would like for the value to be updated with each call. What am I missing?
The design here is based on that your function rely on returning a result.
Which causes a problem because Pyglet's internal functions are in charge of executing that function at a interval, meaning you're not the one executing the call - and there for you're not the one getting that return value, Pyglet is.
And since there's no meaningful way for Pyglet to relay that returned value (there are ways, but they involve hooking in and overriding certain internal functions), you will never see that return value.
The quick and easy workaround would be to do:
x=1.0
def update(dt):
space.step(dt)
def xprinter(self):
global x
print(x)
x += 1
if __name__ == "__main__":
pyglet.clock.schedule(xprinter)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
This way, the schedule call will update the global variable x rather than returning the result of the math equation.
A more neat approach would be to define a class with the x attribute and pass a class instance to the pyglet.clock.schedule():
class player():
def __init__(self):
self.x = 0
def update(dt):
space.step(dt)
def xprinter(self, p):
print(p)
p.x += 1
if __name__ == "__main__":
p = player()
x = pyglet.clock.schedule(xprinter, p)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
And if I'm not completely out of the ball park, this would remember the value across clock ticks, because of the instance.
This is also usually what you'll be using the schedule for, doing player / game / animation updates.

Raspberry Pi - Python - joystick

I am using Raspberry Pi.
while True:
if joystick.get_button(0) == 1:
print ("stop")
else
print ("start")
The purpose of this code is :
I want to interrupt some action while I press a button.
while running the code, it ignores me when I press the button and keep giving me "start". However, if I change the code to :
if joystick.get_button(0) == 0:
the program gives me "stop" at once. (0 is the default value of get_button(0), 1 means I press the button)
The cycle itself seems ok, so I would think that the problem is how your get_button() method acts. Be sure that it is returning the right value and that infinite loop and status checking are not running in the same thread.
Anyway, I would suggest you to use the Observer Pattern.
Basically, it allows you to create a reaction over your joystick button without using infinite loops.
The following code should fit your needs. Joystick class call methods from Player class every time the button is pressed, so every time Joystick change its state.
//OBSERVABLE OBJECT
class Joystick(object):
def __init__(self):
self._button = 0
self._observers = []
def get_button(self):
return self._button
def set_button(self, value):
for callback in self._observers:
callback(self._button)
def bind_to(self, callback):
self._observers.append(callback)
//OBSERVER OBJECT
class Player(object):
def __init__(self, controller):
self._state = 0; //1 - stop, 0 - play
self.controller.bind_to(self.change_state)
def change_state(self, new_state):
self_state = new_state
if(new_state == 0)
print 'play'
else
print 'stop'
This solution will print 'play' and 'stop' once, on every state change.
Then in your code you will create an observable instance:
joystick = new Joystick()
and pass it to an observer:
player = new Player(joystick)
in this way, when you launch your setter function:
joystick.set_button(0)
joystick will automatically change the status in player instance.

Keyevents with self - Python

I have this bit of code here:
from tkinter import *
class player():
def __init__(self, xcoor = 0, ycoor = 0):
self.xcoor = xcoor
def leftKey(self, event):
self.xcoor += 1
print("Right key pressed")
def rightKey(self, event):
self.ycoor += 1
print("Left key pressed")
world = Tk()
p1 = player()
world.bind('<Left>', player.leftKey)
world.bind('<Right>', player.rightKey)
world.mainloop()
When I run this and try the keys, whether right or left, I get this error:
TypeError: leftKey() missing 1 required positional argument: 'event'
Exception in Tkinter callback
I think the error is because (self, event) is wrong, but how do I fix that? I want it such that if an object of this class is created, its xcoor and ycoor will change when calling this function via keybindings.
Bind to the player object’s methods instead:
world.bind('<Left>', p1.leftKey)
world.bind('<Right>', p1.rightKey)
Otherwise, player.leftKey and player.rightKey will refer to the unbound methods that still expect a player object as the first argument (self). By referencing the methods from the player object, that argument is implicitely set. This is the same behavior you get when you just do p1.leftKey(evt) which is really just the same as player.leftKey(p1, evt).

How can I prevent my python game from reiterating and instead carry on?

I've made a simple game using pygame and livewires, where a sprite has to avoid falling mushrooms. The number of mushrooms falling at a certain time is meant to increase as the score increases. Here is what I mean:
from livewires import games,color
import random
games.init(screen_width=633,screen_height=479,fps=50)
class Stick_Man(games.Sprite):
def update(self):
self.x=games.mouse.x
if self.left<0:
self.left=0
if self.right>games.screen.width:
self.right=games.screen.width
self.check_collision()
def check_collision(self):
if self.overlapping_sprites:
self.over_message()
def over_message(self):
b=games.Message(value="Game Over", size=100, color=color.red,x=games.screen.width/2,y=games.screen.height/2,lifetime=250,after_death=games.screen.quit)
games.screen.add(b)
class Mushroom(games.Sprite):
score=0
start=200
score_required=100
level=1
total_score=0
speed=1
mushroom=games.load_image("mushroom.jpg")
x_position=random.randrange(640)
#staticmethod
def next_level():
indicate='Level ', + Mushroom.level, ' cleared'
message=games.Message(value=indicate,size=50,color=color.red,x=games.screen.width/2,y=games.screen.height/2, lifetime=150)
games.screen.add(message)
Mushroom().score_required+=50
Mushroom().score-=Mushroom.score_required
Mushroom().start-=150
Mushroom().speed+=5
Mushroom().level+=1
if Mushroom().start==20:
Mushroom().start+=10
def __init__(self):
super(Mushroom,self).__init__(image=Mushroom.mushroom,x=games.mouse.x,y=0)
def update(self):
self.dy=Mushroom.speed
self.check()
self.check2()
def check(self):
if self.bottom==games.screen.height:
self.destroy()
Mushroom.score+=50
Mushroom.total_score+=Mushroom.score
if Mushroom().score==Mushroom.score_required:
self.next_level()
def check2(self):
if self.top==Mushroom.start:
self.duplicate()
def duplicate(self):
new_mush=Mushroom()
games.screen.add(new_mush)
background_image=games.load_image("background.jpg", transparent=False)
games.screen.background=background_image
stickman_image=games.load_image("stickman.png", transparent=True)
stickman=Stick_Man(image=stickman_image,left=1,bottom=480)
games.screen.add(stickman)
games.mouse.is_visible=False
b=Mushroom()
c=Mushroom()
a=Mushroom()
games.screen.add(b)
games.screen.add(a)
games.screen.add(c)
games.screen.event_brab=True
games.screen.mainloop()
The code is pretty self explanatory and whenever one of the mushrooms is equal to start, then a new object is created thus meaning a new mushroom comes in. However, what happens is that code doesn't function properly a second time and the mushrooms don't get faster spawn much faster either. Also, when the game first starts, the minute the first mushroom hits the bottom it says level one cleared, when it should be after two mushrooms. The sprite is just a red mushroom and also a stickman which can be found on g images if you want to simulate.
So my question is how do i make the object's STATS carry on from where it left off whenever another mushroom appears and also display the message at the right time
Your problem is in all of the lines that look like this:
Mushroom().score_required+=50
There are a number of problems here, which all together add up to make this have no useful effect:
Mushroom() creates a new Mushroom instance (which goes away as soon as this line is done).
Assigning (including update-assigning) to an attribute through an instance always creates or updates an instance attribute, even if there was a class attribute of the same name.
The += operator doesn't mutate immutable values like integers in-place (because that would be impossible); a += b is effectively the same as a = a + b.*
So, when you put that together, what you're doing is creating a new value equal to Mushroom.score_required + 50, then assigning that value to a new instance attribute of a temporary instance (which immediately goes away). This has no effect on the class attribute, or on any of the other instances.
You have a related, but different, problem in the lines like this:
x_position=random.randrange(640)
Unless you want all of the mushrooms to have the same x_position, this should not be a class attribute, but an instance attribute, and you're going to run into all kinds of strange problems.
Storing game stats as class attributes of a random class is a strange thing to do. There are ways you could make that work, but there's no good reason to even try. Class attributes are useful for constants that all instances of the class might as well share, but they're not useful as a substitute for global variables.
A better design would be something like this:
class Game(object):
def __init__(self):
self.score = 0
self.start = 200
self.score_required = 100
self.level = 1
self.total_score = 0
def next_level(self):
indicate = 'Level ', + Mushroom.level, ' cleared'
message = games.Message(value=indicate, size=50, color=color.red,
x=games.screen.width/2, y=games.screen.height/2,
lifetime=150)
games.screen.add(message)
self.score_required += 50
self.score -= self.score_required
self.start -= 150
self.speed += 5
self.level += 1
if self.start == 20:
self.start += 10
def update_score(self, n):
game.score += n
game.total_score += game.score
if self.score == self.score_required:
self.next_level()
class Mushroom(games.Sprite):
mushroom=games.load_image("mushroom.jpg")
def __init__(self, game):
self.x_position=random.randrange(640)
self.game = game
super(Mushroom,self).__init__(image=Mushroom.mushroom,x=games.mouse.x,y=0)
def update(self):
self.dy=Mushroom.speed
self.check()
self.check2()
def check(self):
if self.bottom == games.screen.height:
self.destroy()
game.update_score(50)
def check2(self):
if self.top == Mushroom.start:
self.duplicate()
def duplicate(self):
games.screen.add(Mushroom(self.game))
game = Game()
games.screen.add(Mushroom(game))
games.screen.add(Mushroom(game))
games.screen.add(Mushroom(game))
games.screen.event_brab=True
* That's not completely true. In fact, a = a + b is equivalent to a = a.__add__(b), while a += b is equivalent to a = a.__iadd__(b) if such a method exists, falling back to __add__ only if it doesn't. For mutable objects like lists, this makes a big difference, because __iadd__ can change self in-place and then return it, meaning you end up assigning the same object back to a that was already there. But for immutable objects, there's no difference.

Get the return value from a function in a class in Python

I am trying to simply get the value out of my class using a simple function with a return value, I'm sure its a trivial error, but im pretty new to python
I have a simply class set up like this:
class score():
#initialize the score info
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
# Score Info
def setScore(num):
self.score = num
# Enemy Info
def getEnemies():
return self.num_enemies
# Lives Info
def getLives():
return self.getLives
etc.....
Than I create an instance of the class as such:
scoreObj = score()
for enemies in range(0, scoreObj.getEnemies):
enemy_sprite.add(enemy())
I get the error saying that an integer is expected, but it got an instancemethod
What is the correct way to get this information?
Thanks!
scoreObj.getEnemies is a reference to the method. If you want to call it you need parentheses: scoreObj.getEnemies().
You should think about why you are using a method for this instead of just reading self.num_enemies directly. There is no need for trivial getter/setter methods like this in Python.
The first parameter for a member function in python is a reference back to the Object.
Traditionally you call it "self", but no matter what you call the first parameter, it refers back to the "self" object:
Anytime I get weird errors about the type of a parameter in python, I check to see if I forgot the self param. Been bit by this bug a few times.
class score():
#initialize the score info
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
# Score Info
def setScore(self, num):
self.score = num
# Enemy Info
def getEnemies(self):
return self.num_enemies
# Lives Info
def getLives(foo): #foo is still the same object as self!!
return foo.num_lives
#Works but don't do this because it is confusing
This code works:
class score():
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
def setScore(self, num):
self.score = num
def getEnemies(self):
return self.num_enemies
def getLives(self):
return self.getLives
scoreObj = score()
for enemy_num in range(0, scoreObj.getEnemies()):
print enemy_num
# I don't know what enemy_sprite is, but
# I commented it out and just print the enemy_num result.
# enemy_sprite.add(enemy())
Lesson Learned:
Class functions must always take one parameter, self.
That's because when you call a function within the class, you always call it with the class name as the calling object, such as:
scoreObj = score()
scoreObj.getEnemies()
Where x is the class object, which will be passed to getEnemies() as the root object, meaning the first parameter sent to the class.
Secondly, when calling functions within a class (or at all), always end with () since that's the definition of calling something in Python.
Then, ask yourself, "Why am I not fetching 'scoreObj.num_lives' just like so instead? Am I saving processing power?" Do as you choose, but it would go faster if you get the values directly from the class object, unless you want to calculate stuff at the same time. Then your logic makes perfect sense!
You made a simple mistake:
scoreObj.getEnemies()
getEnemies is a function, so call it like any other function scoreObj.getEnemies()

Categories

Resources