I do not fully understand classes. I have read the python documentation and several other tutorials. I get the basic gist of it but don't understand the nuance. For instance in my code here:
class whiteroom():
""" Pick a door: red, blue, green, or black. """
do = raw_input("> ")
if "red" in do:
print "You entered the red room."
elif "blue" in do:
print "You entered the blue room."
elif "green" in do:
print "You entered the green room."
elif "black" in do:
print "You entered the black room."
else:
print "You sit patiently but slowly begin to stave. You're running out of time."
return whiteroom()
game = whiteroom()
game
(original codepad)
I would like to return the class whiteroom. Which is, either not possible, or not being done correctly. If you could clear up how to return a class or how to "link" two classes together so that whiteroom repeats on the else and the other rooms (which would be classes) are returned when called that would be awesome.
Also I'm super shaky on __init__ and am still not really sure what its purpose is. Everyone keeps telling me that it "initializes", which I'm sure it does, but that doesn't seem to be helping my brain out.
Functions are very different from classes. It looks like you took a function and just changed the def to class. I guess that mostly works in your case, but it's not how classes are supposed to go.
Classes contain functions (methods) and data. For example, you have a ball:
class Ball(object):
# __init__ is a special method called whenever you try to make
# an instance of a class. As you heard, it initializes the object.
# Here, we'll initialize some of the data.
def __init__(self):
# Let's add some data to the [instance of the] class.
self.position = (100, 100)
self.velocity = (0, 0)
# We can also add our own functions. When our ball bounces,
# its vertical velocity will be negated. (no gravity here!)
def bounce(self):
self.velocity = (self.velocity[0], -self.velocity[1])
Now we have a Ball class. How can we use it?
>>> ball1 = Ball()
>>> ball1
<Ball object at ...>
It doesn't look very useful. The data is where it could be useful:
>>> ball1.position
(100, 100)
>>> ball1.velocity
(0, 0)
>>> ball1.position = (200, 100)
>>> ball1.position
(200, 100)
Alright, cool, but what's the advantage over a global variable? If you have another Ball instance, it will remain independent:
>>> ball2 = Ball()
>>> ball2.velocity = (5, 10)
>>> ball2.position
(100, 100)
>>> ball2.velocity
(5, 10)
And ball1 remains independent:
>>> ball1.velocity
(0, 0)
Now what about that bounce method (function in a class) we defined?
>>> ball2.bounce()
>>> ball2.velocity
(5, -10)
The bounce method caused it to modify the velocity data of itself. Again, ball1 was not touched:
>>> ball1.velocity
Application
A ball is neat and all, but most people aren't simulating that. You're making a game. Let's think of what kinds of things we have:
A room is the most obvious thing we could have.
So let's make a room. Rooms have names, so we'll have some data to store that:
class Room(object):
# Note that we're taking an argument besides self, here.
def __init__(self, name):
self.name = name # Set the room's name to the name we got.
And let's make an instance of it:
>>> white_room = Room("White Room")
>>> white_room.name
'White Room'
Spiffy. This turns out not to be all that useful if you want different rooms to have different functionality, though, so let's make a subclass. A subclass inherits all functionality from its superclass, but you can add more functionality or override the superclass's functionality.
Let's think about what we want to do with rooms:
We want to interact with rooms.
And how do we do that?
The user types in a line of text that gets responded to.
How it's responded do depends on the room, so let's make the room handle that with a method called interact:
class WhiteRoom(Room): # A white room is a kind of room.
def __init__(self):
# All white rooms have names of 'White Room'.
self.name = 'White Room'
def interact(self, line):
if 'test' in line:
print "'Test' to you, too!"
Now let's try interacting with it:
>>> white_room = WhiteRoom() # WhiteRoom's __init__ doesn't take an argument (even though its superclass's __init__ does; we overrode the superclass's __init__)
>>> white_room.interact('test')
'Test' to you, too!
Your original example featured moving between rooms. Let's use a global variable called current_room to track which room we're in.1 Let's also make a red room.
1. There's better options besides global variables here, but I'm going to use one for simplicity.
class RedRoom(Room): # A red room is also a kind of room.
def __init__(self):
self.name = 'Red Room'
def interact(self, line):
global current_room, white_room
if 'white' in line:
# We could create a new WhiteRoom, but then it
# would lose its data (if it had any) after moving
# out of it and into it again.
current_room = white_room
Now let's try that:
>>> red_room = RedRoom()
>>> current_room = red_room
>>> current_room.name
'Red Room'
>>> current_room.interact('go to white room')
>>> current_room.name
'White Room'
Exercise for the reader: Add code to WhiteRoom's interact that allows you to go back to the red room.
Now that we have everything working, let's put it all together. With our new name data on all rooms, we can also show the current room in the prompt!
def play_game():
global current_room
while True:
line = raw_input(current_room.name + '> ')
current_room.interact(line)
You might also want to make a function to reset the game:
def reset_game():
global current_room, white_room, red_room
white_room = WhiteRoom()
red_room = RedRoom()
current_room = white_room
Put all of the class definitions and these functions into a file and you can play it at the prompt like this (assuming they're in mygame.py):
>>> import mygame
>>> mygame.reset_game()
>>> mygame.play_game()
White Room> test
'Test' to you, too!
White Room> go to red room
Red Room> go to white room
White Room>
To be able to play the game just by running the Python script, you can add this at the bottom:
def main():
reset_game()
play_game()
if __name__ == '__main__': # If we're running as a script...
main()
And that's a basic introduction to classes and how to apply it to your situation.
I'm sure you've heard all this before, but I'll give it a go.
Classes are a way to group up a bunch of function and variables into a single object. When you get all the way down to it, this is simply a way of organizing everything into groups that make sense. There are benefits down the road for making things easier to understand, debug, extend, or maintain, but basically its just a way to make something more defined in your mental model.
Your code looks like you are trying to write your entire program inside an 'object' (really, you just have an incorrectly written function).
Consider this instead.
Think of your mental model of rooms which have doors to them and whiteboards in them. Doors have a color. Also, whiteboards can have some text written on them. We'll leave it there to be simple.
To me, this suggests 3 different objects -- a door object that has a string for color, a whiteboard object that has a string for the text, and a room object that has a door and a whiteboard.
Consider the following code:
class Door(object):
def __init__(self, color):
self.color = color
class Whiteboard(object):
def __init__(self, default_text=''):
self.text = ''
self.write_text(default_text)
def write_text(self, text):
self.text += text
def erase(self):
self.text = ''
class Room(object):
def __init__(self, doorcolor, whiteboardtext=''):
self.whiteboard = Whiteboard(whiteboardtext)
self.door = Door(doorcolor)
# make a room with a red door and no text on the whiteboard
room1 = Room('red')
# make a room with a blue door and 'yeah, whiteboard' on the whiteboard
room2 = Room('blue', 'yeah, whiteboard')
# make a room with a green door
room3 = Room('green')
# now I can play around with my 'rooms' and they keep track of everything internally
print 'room 1 door color: ' + room1.door.color
print 'room 2 door color: ' + room2.door.color
# all my rooms have a door and a whiteboard, but each one is different and self contained. For example
# if I write on room 1's whiteboard, it doesn't change anything about room 3s
print 'room1 whiteboard: ' + room1.whiteboard.text
print 'room2 whiteboard: ' + room2.whiteboard.text
print 'room3 whiteboard: ' + room3.whiteboard.text
print '-- changeing room 1 whiteboard text --'
room1.whiteboard.write_text('oop is really helpful')
print 'room1 whiteboard: ' + room1.whiteboard.text
print 'room2 whiteboard: ' + room2.whiteboard.text
print 'room3 whiteboard: ' + room3.whiteboard.text
The init function is what gets called when you 'initialize' a new instance of your class. In the example I am making 3 Room objects which each create a Door and Whiteboard object internally. The parameters I pass into the constructor Room(parameter1, parameter2) get passed to the init functions - you can see I'm using this to set the door color and optionally some text on the whiteboard. Also notice that the variables that 'belong' to the objects are referenced with self - this reference is what gets passed in as the first parameter to all class functions (and becomes more important later when you are extending classes and other more advanced things).
You're really far off.
Sorry to say it, but this is just barely salvageable.
From what I can tell you want something like a room class, for instance:
class Room(object):
''' A generic room '''
def __init__(self):
self.choices = None
self.enter()
def enter(self):
''' Enter the room, to be filled out in subclass '''
pass
def print_choices(self):
'''You are stuck bro'''
print "You are stuck bro"
Then you can make a specific room like the whiteroom like so:
class Whiteroom(Room):
''' A white room '''
def __init__(self):
self.choices = ["red", "blue", "green", "black"]
self.enter()
def enter(self):
print "You sit patiently, but slowly begin to starve. You're running out of time."
def print_choices(self):
print "You can choose from the following rooms:"
print self.choices
class Blackroom(Room):
''' A black room '''
def enter(self):
print "It's really dark in here. You're out of time."
class Redroom(Room):
''' A red room '''
def __init__(self):
self.choices = ["black", "blue", "green", "white"]
self.enter()
def enter(self):
print "It's getting hot in here. So take off all your clothes."
def print_choices(self):
print "You can choose from the following rooms:"
print self.choices
class Blueroom(Room):
''' A blue room '''
def __init__(self):
self.choices = ["black", "red", "green", "white"]
self.enter()
def enter(self):
print "It's nice and cool in here. Stay awhile if you want."
def print_choices(self):
print "You can choose from the following rooms:"
print self.choices
class Greenroom(Room):
''' A green room '''
def __init__(self):
self.choices = ["black", "red", "blue", "white"]
self.enter()
def enter(self):
print "You won."
Then you'd have do this to run the game:
print "Type 'quit' to quit"
print "Type 'choices' to see what your choices are"
current_room = Whiteroom()
done = False
while (not done):
entry = raw_input("> ")
if entry == "quit":
done = True
if "choices" in entry:
current_room.print_choices()
if current_room.choices:
if entry in current_room.choices:
if "white" in entry:
current_room = Whiteroom()
if "black" in entry:
current_room = Blackroom()
if "red" in entry:
current_room = Redroom()
if "green" in entry:
current_room = Greenroom()
done = True
if "blue" in entry:
current_room = Blueroom()
That's my best attempt at turning your snippet into an actual game, using classes.
In OOP you have types and objects. Types are abstractions (I would call it idea of) and concrete objects. When you define a class via the syntax class Idea: you identify a type and you can give that type attributes and abilities.
For example:
class Idea:
populare = None
#staticmethod
def change_the_world(atrribute):
return f'a new {attribute} world'
Why is it great and not just a coding style? Just because, in our complex world there are many ideas and even more of the idea of those ideas and so it appears in complex applications. You can have the idea itself as a basement, a mix of other ideas, as a layer in multiple levels of ideas or a hybrid of all that.
As an example:
class Idea:
populare = None
#staticmethod
def change_the_world(atrribute):
return f'a new {attribute} world'
class Freedom(Idea):
populare = True
#classmethod
def desire(cls):
return cls.change_the_world('free')
How powerful this is? You will notice when you think about built-in-types and what all you have done or could do with them. How easy it gets to implement design pattern and to built a whole world that manifests your point of view. But enough of types, there are a concrete objects. They are manifested types with individual identities, so called Entity's.
As example:
class Color:
def __init__(self, name, value):
self.name = None
self.value = None
def less_red(self):
red_portion = self.value[0]
new_value = red_portion-1
self.value = (new_value, self.value[1], self.value[2])
return self.value
my_red = Color('My Red', (255, 0, 0))
Entities can be imagine as manifested idea, that can be identified by themselves. That why the we usually write self as the first parameter in the __init__ it is a hint that this pointer is a reference to itself, not the class but the entity you just initialized.
class Circle():
pi = 3.14
def __init__(self,radius=1):
self.radius = radius
self.area = radius*radius*self.pi
def get_circrumference(self):
return self.radius* self.pi*2
result:
Circle(23)
my_circle = Circle(30)
my_circle.pi =
3.14
my_circle.radius =
30
my_circle.get_circrumference() =
118.4
my_circle.area =
2826.0
help(Circle) =
Help on class Circle in module main:
class Circle(builtins.object)
| Circle(radius=1)
|
| Methods defined here:
|
| init(self, radius=1)
| Initialize self. See help(type(self)) for accurate signature.
|
| get_circrumference(self)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| dict
| dictionary for instance variables (if defined)
|
| weakref
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| pi = 3.14
Here's a simple implementation of cartesian points using class:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, move_x, move_y):
self.x += move_x
self.y += move_y
def scale(self, factor):
self.x *= factor
self.y *= factor
def mod(self):
return (self.x ** 2 + self.y ** 2) ** (1 / 2)
A = Point(3, 4)
print(A.x, A.y) -> 3 4
print(A.mod()) -> 5
A.move(2, 8) #(5, 12)
A.scale(2) #(10, 26)
Related
I'm relatively new with a decent amount of experience and I'm trying to make a text based adventure, I'm making a fighting system and wish to have enemy's that have different abilities. Instead of recreating the fight for a different enemy every time, I'm trying to use interchangeable dictionaries for each enemy. My goal is to create a function call that varies depending on what enemy is in the fight without getting into objects. I have an example below and would like to know if there is a way to do something similar.
wolf = {'ability': 'bite'}
bear = {'ability': 'claw'}
enemy = {}
def claw():
print('stuff')
def bite():
print('different stuff')
def use_ability():
enemy = wolf
enemy['ability']()
use_ability()
In python functions are first class objects. You can just use them as values in your dictionary.
wolf = {'ability': bite}
bear = {'ability': claw}
However be careful as there is no forward referencing in python. So make sure you define your functions before you assign them to a dictionary.
def claw():
print('stuff')
def bite():
print('different stuff')
wolf = {'ability': bite}
bear = {'ability': claw}
def use_ability():
enemy = wolf
enemy['ability']()
use_ability()
You can do it:
def claw():
print('stuff')
def bite():
print('different stuff')
wolf = {'ability': bite}
bear = {'ability': claw}
def use_ability(enemy):
enemy['ability']()
use_ability(wolf)
# different stuff
It really doesn't mean you should do it this way, though.
Use Object-Oriented programming. If you only want to use dicts and functions, you probably should write Javascript instead.
I can't help myself but to make a little program explaining how it should be done in an Object Orientated Language:
You should look up some guides how OOP-Languages work, because when making a game it will be really helpfull if you do it that way
http://www.python-course.eu/object_oriented_programming.php
# This is the SUPERCLASS it holds functions and variables
# that all classes related to this object use
class Enemy(object):
# Here we initialise our Class with varibales I've given an example of how to do that
def __init__(self, HP, MAXHP, ability):
self.HP = HP
self.MAXHP = MAXHP
self.ability = ability
# This function will be used by both Bear and Wolf!
def use_ability(self):
print(self.ability)
# This is our Wolf Object or Class
class Wolf(Enemy):
# Here we init the class inheriting from (Enemy)
def __init__(self, ability, HP, MAXHP):
super().__init__(HP, MAXHP, ability)
# Here we call the superfunction of this Object.
def use_ability(self):
super().use_ability()
# Same as Wolf
class Bear(Enemy):
def __init__(self, ability, HP, MAXHP):
super().__init__(HP, MAXHP, ability)
def use_ability(self):
super().use_ability()
# How to init Classes
wolf_abilities = 'bite'
w = Wolf(wolf_abilities, 10, 10)
bear_abilities = 'claw'
b = Bear(bear_abilities, 10, 10)
# How to use methods from Classes
b.use_ability() # This will print 'bite'
w.use_ability() # This will print 'claw'
I am making a basic RPG style game. I have made different classes for the various parts of the code, one for each of the main items involved (hero, door, monsters etc.)
For both the hero and door, i assign them random locations, shown below in the code, but for the door I run a while loop which makes sure that the door is a certain distance from the hero (using pythagorus).
However the while loop in the door class won't work as it always uses a value of 0 for both heroC and heroR (row and column of the hero). I am relatively new to using classes, but it doesnt seem to make sense as in HeroLocation I assign a random integer to these variables, and HeroLocation is called before DoorLocation.
Any help would be greatly appreciated!!
class Hero(Character):
def __init__(self):
super(Hero, self).__init__(10, 10, 1, 1, 0, 1)
self.herolocations = list(range(1,6)) + list(range(10,14))
self.heroC = 0
self.heroR = 0
def HeroLocation(self):
#place hero
self.heroC = random.choice(self.herolocations)
self.heroR = random.choice(self.herolocations)
class Door:
def __init__(self):
self.hero = Hero()
self.doorC = 0
self.doorR = 0
def DoorLocation(self):
while ((self.hero.heroC-self.doorC)**2+(self.hero.heroR-self.doorR)**2) <= 128:
self.doorC = random.randint(1, 13)
self.doorR = random.randint(1, 13)
class game:
def __init__(self, parent):
self.hero = Hero()
self.door = Door()
def MakeMap(self):
self.hero.HeroLocation()
self.herol = self.Main_game.create_image(15+30*self.hero.heroC,15+30*self.hero.heroR, image = self.heroimage)
self.door.DoorLocation()
self.doorl = self.Main_game.create_image(15+30*self.door.doorC,15+30*self.door.doorR, image = self.exitdoor)
NB there is a lot more code, but i have only posted what i felt was the relevant stuff, if you need more to crack the puzzle message me!
You are not calling the good Hero instance in Door.DoorLocation.
Btw I really advice you to change class & methods name following Pep 8.
In Door.__init__, first line:
self.hero = Hero()
Here, you are instantiating a new Hero's instance. But, in game.MakeMap you are calling self.hero.HeroLocation().
This self.hero instance is not the same, because it was instantiated in game.__init__ and not in Door.__init__.
I didn't try, but check what behaviour gives this update:
class game:
def __init__(self, parent):
self.door = Door()
self.hero = self.door.hero
With this you now are calling the instance defined in Door.__init__, so when doing self.hero.HeroLocation() in game and (self.hero.heroC-self.doorC [...] in Door you are pointing the same instance.
Last thing, this solution may works, but is surely not what you really wants, I think a door should not store a hero, a hero should not store a door too, but here is more complex question about patterns.
So I was having some trouble with some code I'm doing for a basic game that I'm writing in my learning of Python (original question here if it helps).
After a lot of playing around with it, I realized my problem. I don't actually know how to do a "has-a" when trying to let one object (a character) "have" an object of another class (such as a weapon).
If I want, say a Char (character) called dean to do an action specific to the weapon he has. How would I give that object (the Char dean) an object of class "Weapon"?
Thank you.
Edit:
I've found that I can do this by passing the "Weapon" in question as an argument. i.e.:
dean = Char("Dean", hanzo_blade)
Then having Char init with (self, name, weapon).
However, I want the user to choose, from a selection, which weapon the character gets. So I'm not sure if the content of the Char(_____) can be determined on a dynamic basis from user input. If it's possible, how can I do that? If not, what do I do?
Thanks again.
Edit 2: Here is the pertinent code:
class Char(object):
def __init__(self, name):
self.name = name
self.hp = 300
self.mp = 10
self.strn = 1
self.dex = 1
self.armor = 0
self.xp = 0
self.items = []
self.spells = []
self.weapon = sword() # Assume sword is the default. Alternatively, how might I let this default to nothing?
class Weapon(Equip):
impact = 1
sharp = 1
def __init__(self, name):
self.name = name
hanzo_blade = Weapon("Hanzo Blade")
hanzo_blade.wgt = 3
hanzo_blade.impact = 1
hanzo_blade.sharp = 9
dean = Char("Dean")
dean.strn = 3
dean.dex = 8
If hanzo_blade is one option, how could I let the player, for instance, select that Weapon for the Char dean?
Are you aware of the raw_input builtin? (input in Python 3)
# We assume we already have sword, fists, and stern_glare objects
# representing weapons.
weapons = {'sword': sword, 'fists': fists, 'stern glare': stern_glare}
# Prompt for a choice, and keep prompting until you get a valid choice.
# You'll probably want a more user-friendly prompt.
valid_choice = False
while not valid_choice:
weapon_choice = raw_input('Select your weapon')
valid_choice = weapon_choice in weapons
# Create the character.
dean = Char('Dean', weapons[weapon_choice])
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.
I just started learning python and I am hoping you guys can help me comprehend things a little better. If you have ever played a pokemon game for the gameboy you'll understand more as to what I am trying to do. I started off with a text adventure where you do simple stuff, but now I am at the point of pokemon battling eachother. So this is what I am trying to achieve.
Pokemon battle starts
You attack target
Target loses HP and attacks back
First one to 0 hp loses
Of course all of this is printed out.
This is what I have for the battle so far, I am not sure how accurate I am right now. Just really looking to see how close I am to doing this correctly.
class Pokemon(object):
sName = "pidgy"
nAttack = 5
nHealth = 10
nEvasion = 1
def __init__(self, name, atk, hp, evd):
self.sName = name
self.nAttack = atk
self.nHealth = hp
self.nEvasion = evd
def fight(target, self):
target.nHealth - self.nAttack
def battle():
print "A wild appeared"
#pikachu = Pokemon("Pikafaggot", 18, 80, 21)
pidgy = Pokemon("Pidgy", 18, 80, 21)
pidgy.fight(pikachu)
#pikachu.fight(pidgy)
Full code here: http://pastebin.com/ikmRuE5z
I am also looking for advice on how to manage variables; I seem to be having a grocery list of variables at the top and I assume that is not good practice, where should they go?
If I was to have fight as a instance method (which I'm not sure I would), I would probably code it up something like this:
class Pokemon(object):
def __init__(self,name,hp,damage):
self.name = name #pokemon name
self.hp = hp #hit-points of this particular pokemon
self.damage = damage #amount of damage this pokemon does every attack
def fight(self,other):
if(self.hp > 0):
print("%s did %d damage to %s"%(self.name,self.damage,other.name))
print("%s has %d hp left"%(other.name,other.hp))
other.hp -= self.damage
return other.fight(self) #Now the other pokemon fights back!
else:
print("%s wins! (%d hp left)"%(other.name,other.hp))
return other,self #return a tuple (winner,loser)
pikachu=Pokemon('pikachu', 100, 10)
pidgy=Pokemon('pidgy', 200, 12)
winner,loser = pidgy.fight(pikachu)
Of course, this is somewhat boring since the amount of damage does not depend on type of pokemon and isn't randomized in any way ... but hopefully it illustrates the point.
As for your class structure:
class Foo(object):
attr1=1
attr2=2
def __init__(self,attr1,attr2):
self.attr1 = attr1
self.attr2 = attr2
It doesn't really make sense (to me) to declare the class attributes if you're guaranteed to overwrite them in __init__. Just use instance attributes and you should be fine (i.e.):
class Foo(object):
def __init__(self,attr1,attr2):
self.attr1 = attr1
self.attr2 = attr2v
You don't need the variables up the top. You just need them in the init() method.
The fight method should return a value:
def fight(self, target):
target.nHealth -= self.nAttack
return target
You probably want to also check if someone has lost the battle:
def checkWin(myPoke, target):
# Return 1 if myPoke wins, 0 if target wins, -1 if no winner yet.
winner = -1
if myPoke.nHealth == 0:
winner = 0
elif target.nHealth == 0:
winner = 1
return winner
Hope I helped.
I am only going to comment on a few obvious aspects, because a complete code review is beyond the scope of this site (try codereview.stackexchange.com)
Your fight() method isn't saving the results of the subtraction, so nothing is changed. You would need to do something like this:
def fight(target, self):
target.nHealth -= self.nAttack
# check if target is dead now?
I might even recommend not imposing a modification on your target directly. It may be better if you can call an attack(power) on your target, and let it determine how much damage is done. You can then check if the target is dead yet. Ultimately I would think you would have some "dice" object that would determine the outcomes for you.
As for globals... just stop using them. It is a bad habit to have them unless you really have a good reason. Have functions that return results to the caller, which you then make use of:
def func(foo):
return 'bar'
You can however have a module of constants. These are a bunch of values that don't change for the life of the application. They are merely variables that provide common values. You might create a constants.py and have stuff like:
UP = "up"
DOWN = "down"
DEAD = 0
...
... And in your other modules you do:
from constants import *