[Tutor] Passing a Variable

Lie Ryan lie.1296 at gmail.com
Mon Apr 4 15:27:38 CEST 2011


On 04/04/11 11:55, Ryan Strunk wrote:
> Hi list,
> 
> I am in the midst of trying to code a game based entirely on audio cues, and
> I've run into a bit of a snag when trying to monitor certain variables. I'll
> lay out the framework of what I'm going for in the hope that it makes sense
> when written down.
> In a standard video game I could have a health bar go from normal to yellow
> to red as it diminishes. In audio, though, I don't have that luxury. As a
> result, I have conceptualized a system whereby a player hears a sound every
> so often if a particular stat drops into the caution range. If the player
> drops into the danger range, the sound loops continuously. I also wanted to
> make sure that if the player dropped from caution to danger, there wasn't a
> big, awkward pause in the sound loop and that the player would know
> immediately that his stat had dropped (see first and second if checks in the
> check method).
> The problem:
> My existing methods directly update stats. For example: the player class has
> a self.health stat which is directly affected by other methods. This has
> caused no problem up until now. When I pass self.health to the code I will
> paste below, however, the Statistic class does not receive health, but
> rather health's value.
> I understand that python passes variables by value and not by reference, and
> this has not been a problem up until now. Now that I am trying to design a
> class which explicitly checks a specific variable, though, I can't fathom a
> way to do it unless I pass a direct reference, and I'm not sure that can be
> done. I need to figure out a way for the below code to check the value of
> the health variable and act on it. This way, if player's self.health
> changes, the static class will take note of that and respond accordingly.
> It occurred to me to make Statistic a child of int, but I'm told that's more
> trouble than I probably want to deal with.
> Any suggestions/advice anyone has would be greatly appreciated.

Rather than having Statistic polling the Player's health, I suggest that
the Player object should call a method in Statistic class when its
health changes, and then the Statistic class can see if the value change
is relevant or not (e.g. whether to start playing audio, or not).

Since you said that you modified self.health directly, in some other
languages this might cause you problems. But behold, this is python, you
can easily turn your attribute into property:

class Player(object):
    def __init__(self):
        self.stat = Statistic()
        self._health = 100

    @property
    def health(self):
        return self._health
    @health.setter
    def health(self, value):
        self.stat.health_changed(self, value)
        self._health = value


class Statistic(object):
    def __init__(...): ...
    def health_changed(self, player, value):
        if value < player.health:
            play_once('taking damage')
        elif value > player.health:
            play_once('getting healed')

        if value < self.low:
            self.status = 'danger'
            play_repeat('danger')
        elif value < self.mid:
            self.status = 'warning'
            play_repeat('warning')
        else:
            self.status = 'safe'
            play_stop()

> Best,
> Ryan
> 
> import sound_lib
> from game_utils import delay
> #this encapsulates threading.Timer's assignment and start method
> 
> class Statistic(object):
> 
>     def __init__(self, stat=None, sound=None, low=None, mid=None,
> high=None):
>         self.stat = stat
>         self.sound = sound
>         self.low = low
>         self.mid = mid
>         self.high = high
>         self.status = 'safe'
>         self.auto_check_timer = None
> 
>     def auto_check(self):
>         if self.stat > self.high:
>             self.status = 'safe'
>             return
>         if self.mid <= self.stat <= self.high:
>             self.status = 'caution'
>             self.sound.play(True)
>             self.auto_check_timer =
> delay(self.sound.bytes_to_seconds(len(self.sound))*2, self.auto_check)
>             return
>         if self.low <= self.stat < self.mid:
>             self.status = 'danger'
>             self.sound.play(True)
>             self.auto_check_timer =
> delay(self.sound.bytes_to_seconds(len(self.sound)), self.auto_check)
> 
>     def check(self):
>         if self.status = 'caution' and self.low <= self.stat < self.mid:
>             #This will set the program to start a constant alarm when the
> stat level has dropped below caution
>             self.auto_check_timer.cancel()
>         if self.sound.is_playing:
>             #to assist in setting up the caution to danger transition
>             #a standard playing sound will have a timer running alongside
> it, so skip the next guard and return
>             if self.auto_check_timer.is_alive() == False:
>                 #guard to make sure program doesn't catch every playing
> sound, should prevent repeated checks from recalling auto_check
>                 sound_duration =
> self.sound.bytes_to_seconds(len(self.sound)) -
> self.sound.bytes_to_seconds(self.sound.position)
>                 self.auto_check_timer = delay(sound_duration,
> self.auto_check)
>             return
>         if self.auto_check_timer == False:
>             #if the timer has never been called, call auto_check
>             self.auto_check()
>             return
>         if self.auto_check_timer.is_alive == True:
>             #there's already a timer running. return
>             return
>         #If it gets this far, it's because the timer already ran, the player
> is 'safe', and another check is being performed
>         self.auto_check()
> 
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
> 




More information about the Tutor mailing list