pygame - How to group sprites - python

Having a real struggle getting this sorted. Had look at some other answers, and I get an error saying that I have too many arguments.
Class containing the objects I want to add.
class Digimon(pygame.sprite.Sprite):
def __init__(self,age,weight,strength,defence,speed,intelligence, image):
self.age = age
self.weight = weight
self.strength = strength
self.defence = defence
self.speed = speed
self.intelligence = intelligence
self.image = image
Have tried to do:
class Digimon(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,age,weight,strength,defence,speed,intelligence, image)
self.age = age
self.weight = weight
self.strength = strength
self.defence = defence
self.speed = speed
self.intelligence = intelligence
self.image = image
but I error regarding the amount of arguments. (1 given, 7 needed).
Player = Digimon(0,2,0,0,0,0, [pygame.image.load("images/koro_1.png"), pygame.image.load("images/koro_2.png"), pygame.image.load("images/koro_3.png") ] )
This is in example of an object which I want to group together. From this, I'll be able to add keyboard events which affect all the objects grouped.
Any help would be fantastic :D
edit: full code: http://pastebin.com/uPWEM8bD

pygame.sprite.Sprite.__init__(self,age,weight,strength,defence,speed,intelligence, image)
The base Sprite class has no need for your age/weight/etc variables. Just pass in self:
pygame.sprite.Sprite.__init__(self)

You have 8 arguments (7 number variables and an image) in the definition but when you call it you pass 7 (6 ints and a list of images).

Related

Text-Based Pokemon Game: How do I implement an evolution system?

I have starting working on this Text-Based Pokemon game and I am stuck on trying to figure an evolution system that can change one class object into another class object, if that makes sense.
I've attempted to do this just by simply making the class object equal to the one I want to change:
# Trainer
new_trainer = Trainer('Trainer', 'Male')
# Test pokemon (the parameter is just a level value)
bulbasaur = Bulbasaur(10)
ivysaur = Ivysaur(20)
# Adding pokemon to party
new_trainer.add_pokemon(bulbasaur)
new_trainer.add_pokemon(ivysaur)
# Display pokemon lists
print(new_trainer.pokemon_list)
new_trainer.display_party()
# Attempting to 'evolve' bulbasuar
bulbasaur = Ivysaur(bulbasaur.lvl)
# Displaying results again to see if it worked
print(new_trainer.pokemon_list)
new_trainer.display_party()
But by looking at the output, it shows that nothing has happened:
Bulbasaur was added to your party!
Ivysaur was added to your party!
[<__main__.Bulbasaur object at 0x0000023587EDA080>, <__main__.Ivysaur object at 0x0000023587EDA0F0>]
1. Bulbasaur
2. Ivysaur
[<__main__.Bulbasaur object at 0x0000023587EDA080>, <__main__.Ivysaur object at 0x0000023587EDA0F0>]
1. Bulbasaur
2. Ivysaur
EDIT:
It turns that that the variable value DOES indeed change, but I simply need to update the Trainer's pokemon list. However, I am still unsure on how to do this.
The display_party function in the Trainer class looks like this:
def display_party(self): # Displays pokemon party list
if not self.pokemon_list:
return print("There are no pokemon in your party.")
else:
for pokemon in range(len(self.pokemon_list)):
print("{0}. {1}".format(pokemon + 1, self.pokemon_list[pokemon].name))
I was just thinking of adding an update_party function, which goes into the list, deletes the old value and inserts the new value, but how will it know what value to delete?
Perhaps there is a better way to do this? And sorry if my question doesn't include that much information, I will add more of my code if it doesn't make much sense already. This is my first time asking a question here :D
EDIT 2:
For those who don't understand how the code works, this is basically how it works so far:
# Formula used to calculate pokemon health
def health_stat_calculation(base_stat, lvl):
return int(((base_stat * 3 * lvl) / 100) + lvl + 10)
# Formula used to calculate pokemon stats
def stat_calculation(base_stat, lvl):
return int(((base_stat * 3 * lvl) / 100) + 5)
# Trainer class
class Trainer:
def __init__(self, name, gender):
self.name = name
self.gender = gender
self.pokemon_list = []
self.item_list = []
def add_badge(self, badge): # Gives player a badge
self.player_badges.append(badge)
def add_pokemon(self, pokemon): # Adds a pokemon to party
for poke in self.pokemon_list:
if pokemon is poke:
return print("You already have this pokemon in your party!")
if len(self.pokemon_list) > 5:
return print("You have too much pokemon in your party!")
else:
self.pokemon_list.append(pokemon)
return print("{} was added to your party!".format(pokemon.name))
def display_party(self): # Displays pokemon party list
if not self.pokemon_list:
return print("There are no pokemon in your party.")
else:
for pokemon in range(len(self.pokemon_list)):
print("{0}. {1}".format(pokemon + 1, self.pokemon_list[pokemon].name))
def add_item(self, item): # Adds an item to player's inventory
if len(self.item_list) > 50:
print("You have too much items in your inventory!")
else:
self.item_list.append(item)
print("{} was added to your inventory!")
# Generic pokemon class
class Pokemon:
def __init__(self, name, lvl, exp, id_number, health, attack, defence, sp_attack, sp_defense, speed):
self.name = name
self.lvl = lvl
self.exp = exp
self.id_number = id_number
self.health = health
self.attack = attack
self.defence = defence
self.sp_attack = sp_attack
self.sp_defense = sp_defense
self.speed = speed
def get_pokemon_name(self):
return self.name
# User friendly stat display
def display_stats(self):
print("\nStats for {}\n---------------".format(self.name))
print("Level: {}".format(self.lvl))
print("Index No.{}".format(self.id_number))
print("Health: {}".format(self.health))
print("Attack: {}".format(self.attack))
print("Defense: {}".format(self.defense))
print("Sp. Attack: {}".format(self.sp_attack))
print("Sp. Defense: {}".format(self.sp_defense))
print("Speed: {}\n".format(self.speed))
# Level up pokemon and show change in stats
def level_up(self):
self.display_stats()
self.lvl += 1
print("\n{} has leveled up!\n".format(self.name))
self.calculate_stats()
self.display_stats()
# Calculate generic pokemon stats
def calculate_stats(self):
self.health = health_stat_calculation(self.base_health, self.lvl)
self.attack = stat_calculation(self.base_attack, self.lvl)
self.defense = stat_calculation(self.base_defense, self.lvl)
self.sp_attack = stat_calculation(self.base_sp_attack, self.lvl)
self.sp_defense = stat_calculation(self.base_sp_defense, self.lvl)
self.speed = stat_calculation(self.base_speed, self.lvl)
# Bulbasaur class
class Bulbasaur(Pokemon):
def __init__(self, lvl, name="Bulbasaur"):
self.name = name
self.lvl = 16
self.exp = 0
self.id_number = 1
# Bulbasaur Base stats
self.base_health = 45
self.base_attack = 49
self.base_defense = 49
self.base_sp_attack = 65
self.base_sp_defense = 65
self.base_speed = 45
self.calculate_stats()
# Ivysaur class
class Ivysaur(Pokemon):
def __init__(self, lvl, name="Ivysaur"):
self.name = name
self.lvl = 16
self.exp = 0
self.id_number = 2
# Bulbasaur Base stats
self.base_health = 60
self.base_attack = 62
self.base_defense = 63
self.base_sp_attack = 80
self.base_sp_defense = 80
self.base_speed = 60
self.calculate_stats()
Casting from one class to another makes no sense in your case.
Just go with
class Pokemon():
def __init__(self, name, level=0):
self.level = level
self.name = name
def evolve(self):
self.level += 1
def __str__(self):
return 'Pokemon: {}, Level: {}'.format(self.name, self.level)
p1 = Pokemon('Bulbasaur')
p2 = Pokemon('Ivysaur')
print(p1)
print(p2)
p1.evolve()
p2.evolve()
print(p1)
print(p2)
You could turn the kind, Bulbasaur, Ivysaur, etc., into a component of the Pokemon class. The Bulbasaur has its next evolution stage as an attribute and in the evolve method of the Pokemon you can just set the kind to the next evolution stage.
class Pokemon:
def __init__(self, kind, level):
self.level = level
self.kind = kind # The kind is just a component now.
def evolve(self):
# Create a new instance of the next evolution stage
# and use it to replace the previous kind.
self.kind = self.kind.evolution_stage()
class Bulbasaur:
def __init__(self):
self.base_health = 45
# A reference to the next evolution stage class.
self.evolution_stage = Ivysaur
class Ivysaur:
def __init__(self):
self.base_health = 60
# self.evolution_stage = Venusaur
# Pass a Bulbasaur instance as the `kind` argument.
pokemons = [Pokemon(Bulbasaur(), 3)]
print(pokemons[0].kind, pokemons[0].kind.base_health)
pokemons[0].evolve() # Changes the .kind attribute.
print(pokemons[0].kind, pokemons[0].kind.base_health)
I don't know if this is the cleanest way, but somehow it worked when I added this function into the Pokemon class and used the dict dunder to update the contents of the old object to the new one. The temp_pos was used as a temporary placeholder for the current object's name so it didn't get changed when updating it to the new_pokemon object.
# Evolve function
def evolve(self, evln, trainer):
temp_name = self.name
new_pokemon = evln(self.lvl)
self.__dict__.update(new_pokemon.__dict__)
self.name = temp_name

Printing my Class attributes

these are 2 parts of my misbehaving text based adventure code that I'm trying to learn how to do with a youtube tutorial. I believe that most of my problems arise because the tutorial I'm pretty sure is using python2.something and I'm using 3.
My problem is I'm trying to list the "Player" class attributes on the start screen, which I have successfully done with Playername, but I'm having trouble getting the numbers listed as self.attack and self.health etc to print.
I downloaded python for the first time about 5 days ago, so bear with a noob if you can, please.
Let me know what I can change, and thank you in advance!
class Player:
def _init_(self, name):
self.name = name
self.maxhealth = 100
self.health = self.health
self.attack = 10
self.gold = 0
self.bandages = 0
def start1():
os.system("cls")
print("Name: %s" % (PlayerIG))
print("Attack: {}".format (PlayerIG.attack))
print('Health: {}/{}'.format(PlayerIG.health, PlayerIG.maxhealth))
print("Gold: %i") % PlayerIG.gold
print("Bandages: %i") % PlayerIG.bandages
A few things immediately:
def _init_ needs to be def __init__ (note the double underscores).
self.health = self.health doesn't make sense - whatever is on the right side of an = needs to exist before you can assign some other variable to it, and self.health doesn't exist until that line.
The variable PlayerIG was never assigned to anything, so none of the code in start1 will work (unless it was done somewhere else, that you haven't included in the question).
A working version of what you have in your question would be something like
class Player:
def __init__(self, name, maxhealth, health, attack, gold, bandages):
self.name = name
self.maxhealth = maxhealth
self.health = health
self.attack = attack
self.gold = gold
self.bandages = bandages
def start1():
PlayerIG = Player('foo', 100, 50, 10, 0, 0)
print('Name: {}'.format(PlayerIG.name))
print('Health: {}/{}'.format(PlayerIG.health, PlayerIG.maxhealth))
print('Attack: {}'.format(PlayerIG.attack))
print('Gold: {}'.format(PlayerIG.gold))
print('Bandages: {}'.format(PlayerIG.bandages))
start1()
There are many improvements you could make from there, like defining a __str__ function for Player or using keyword arguments in your __init__ method.

Where did it go wrong in my code?

class Player:
def __init__(self):
self.speed
self.hp
def Berserker(self):
self.speed == 12
self.hp == 6
print("Berserkers stats are: " + Berserker())
So, What have I done wrong? As you can see, I'm very new to Python.
The error I'm getting is: TypeError: Berserker() missing 1 required positional argument: 'self'
You're missing quite a few things, but I'll help you out!
Your __init__ function doesn't do anything. Let's give it some base stats. I'll say that a Player's default speed and health will be 10 and 100, respectively. Then we'll make Berserker a subclass of Player (I think that's what you were going for?). And lastly, I'll give Player a method that will allow you to get a string-formatted output for its values.
First, the new Player:
class Player:
def __init__(self, speed=10, health=100):
self.speed = speed
self.health = health
def __str__(self):
return "A player with speed {} and health {}.".format(self.speed, self.health)
And now for the Berserker. I'll give it a base speed of 15 and health of 85. (Obviously the specifics are up to you!)
class Berserker(Player):
def __init__(self):
super().__init__(speed=15, health=85)
Lastly, we can create these and print the value. I'll make a couple different versions so you can see how it works. (And I'll use the regular Python interpreter for this).
>>> p1 = Player()
>>> p2 = Player(7, 120)
>>> b = Berserker()
>>> print(p1)
A player with speed 10 and health 100.
>>> print(p2)
A player with speed 7 and health 120.
>>> print(b)
A player with speed 15 and health 85.
Hopefully this gives you a good place to start!
You did a bunch of mistakes there :
Indent your Berserker method to be part of the class
Assignement in python is with one "=" not with "==" ( like most programming languages actually )
Give speed and hp initial values or don't put them in the constructor at all , in python variables are created when they're assigned a value.
Make your Berserker method return a string to be able to print it
Create an instance of your class
a working version of you code should be like this :
class Player:
def __init__(self):
self.speed = 0
self.hp = 0
def Berserker(self):
self.speed = 12
self.hp = 6
return "speed {} hp {}".format(self.speed,self.hp)
m = Player()
print("Berserkers stats are: " + m.Berserker())
Now that's a working version but it's still poorly designed IMO ,this is better :
class Player:
def __init__(self):
self.speed = 0
self.hp = 0
def Berserker(self):
self.speed = 12
self.hp = 6
def __str__(self):
return "speed {} hp {}".format(self.speed,self.hp)
m = Player()
m.Berserker()
print(m)

passing self to another classes function in self's function

I have two classes, the first one has a function move(creature, board). Then in the creature class there is a function that calls move, so how do I pass the current creature to the move function while in the creature class? Should it just be move(self, self.board), because when I try that I get a "Undefined variable from import:
move" error?
Here's the relevant code:
Creature:
class creature:
def __init__(self, social, intelligence, sensory, speed, bravery, strenght, size):
self.traits = [social, intelligence, sensory, speed, bravery, strenght]
self.x = 0
self.y = 0
self.hunger = 10
self.energy = 30
self.shelter = 0
self.dominance = 0
self.boardSize = size - 1
self.SOCIAL = 0
self.INTELLIGENCE = 1
self.SENSORY = 2
self.SPEED = 3
self.BRAVERY = 4
self.STRENGTH = 5
...
def performAction(self, action, location):
...
if action == "storeFood":
food = location.vegetation
location.vegetation = -1
simulation.move(self, self.shelter)
self.shelter.foodStorage += food
...
Simulation:
class simulation():
def __init__(self, x):
self.creatures = {creature.creature():"", creature.creature():"", }
self.map = land.landMass
self.lifeCycles = x
self.runStay = ["rfl", "rbf", "rbl", "rbf", ]
self.befriend = ["bbl", "bbf"]
self.fight = ["fbl", "fbf", "bfl", "bff", "ffl", "fff"]
...
def move(self, creature, target):
map[creature.x][creature.y].creatures.remove(creature)
creature.energy -= abs(map[creature.x][creature.y].elevation - target.elevation) / creature.getSpeed()
target.creatures.append(creature)
creature.x, creature.y = target.location
...
EDIT:
OK so I have somewhat solved the problem. Python requires that I have simulation.simulation.map(self, self.shelter) I'm assuming this means that it requires not just the class file but also an instance of that class. So the new question is do I have to make that instance somewhere else then pass it in? Or will this work with an instance of Simulation somewhere else?
Inherit the simulation class into the creature class:
class Creature(Simulation): # I have inherited the functions from Simulation into Creature
...
Now instead of simulation.move(self, self.shelter), you want:
self.move(yourparameters)
If you noticed, I capitalised your class names. It's good to do so.
For more on inheritance in classes, take a look [at the docs].(http://docs.python.org/2/tutorial/classes.html#inheritance)

Creating a circular reference

I need to create several objects that have (often circular) references to each other. In general, several objects might be involved, but here's one simple case where I need just a pair of cars that refer to each other:
class Car:
def __init__(self, position, speed):
self.position = position
self.speed = speed
def set_reference(self, other_car):
self.other_car = other_car
# ...
def main():
# ...
car1 = Car(pos1, spd1)
car2 = Car(pos2, spd2)
car1.set_reference(car2)
car2.set_reference(car1)
A car without a reference to the other car is not a valid object. So ideally, I'd like to perform set_reference from inside the __init__ method; this would be both safer (no chance of using invalid objects) and cleaner (all initialization will be performed in __init__ as one might expect).
Is there any neat solution that achieves this goal? I don't mind creating a pair of cars at once, but each car is a standalone entity, and so it needs to be an instance in its own right.
I'm also aware that circular references are troublesome for GC; I'll deal with that.
Use case:
Each car serves as a backup for the other. Car instances are "smart", i.e., they can do a lot of work. It's annoying if the a car instance doesn't know its backup, since it prevents a car from completing actions without requiring a reference from outside every time.
I don't think there is a good way to move the set_reference() call into __init__(), because the other car might not yet exist. I would probably do something like this.
class Car:
def __init__(self, position, speed):
self.position = position
self.speed = speed
def set_reference(self, other_car):
self.other_car = other_car
#classmethod
def create_pair(cls, car1_args, car2_args):
car1 = cls(*car1_args)
car2 = cls(*car2_args)
car1.set_reference(car2)
car2.set_reference(car1)
return car1, car2
def main():
car1, car2 = Car.create_pair((pos1, spd1), (pos2, spd2))
Here is how you could expand this same concept for a larger circular reference structure:
class Car:
# ...
#classmethod
def create_loop(cls, *args):
cars = [cls(*car_args) for car_args in args]
for i, car in enumerate(cars[:-1]):
car.set_reference(cars[i+1])
cars[-1].set_reference(cars[0])
return cars
You could then call it like this (with any number of cars):
car1, car2, car3 = Car.create_loop((pos1, spd1), (pos2, spd2), (pos3, spd3))
You should up with the references set up like this:
>>> car1.other_car is car2 and car2.other_car is car3 and car3.other_car is car1
True
I'd suggest separating the car data structure from the data structure that references a sequence of cars. other_car doesn't really seem like data that strictly belongs in car, but rather represented in some iterable sequence of cars. Thus the simplest and most logically consistent solution would be to define a car, then put it in a sequence of cars.
If you really don't want to use a factory method, then the only real option is to force the user to configure them afterwards. (Taking on-board what you said about potentially wanting loops of dependency in the comments):
class Car:
def __init__(self, position, speed):
self.position = position
self.speed = speed
#staticmethod
def setup(*args):
for car, next in zip(args, args[1:]):
car.other_car = next
args[-1].other_car = args[0]
def main():
...
car1 = Car(pos1, spd1)
car2 = Car(pos2, spd2)
Car.setup(car1, car2)
Another option is to split off the grouping:
class CarGroup(list):
def other_car(self, car):
index = self.index(car)+1
index = 0 if index >= len(self) else index
return self[index]
class Car:
def __init__(self, position, speed, group):
self.position = position
self.speed = speed
self.group = group
self.group.append(self)
#property
def other_car(self):
return self.group.other_car(self)
def main():
...
group = CarGroup()
car1 = Car(pos1, spd1, group)
car2 = Car(pos2, spd2, group)

Categories