Sprite Values Must Move - python

I have a sprite and when it collides with another object I want it to increase the score that the user gets. However I am unsure how to export the fact that the sprite has collided to another part of my program. This is what I tried:
def checkCollision(self, sprite):
if self.rect.colliderect(sprite.rect):
self.x=3000
self.score=score+100
However it ignore the fact the score has increased despite me having made score global.
Any help would be appreciated.

I'm assuming that the collision function you provided is part of your player class. Making that assumption, you could simply assign the global score to = x.score (x = whatever you named that particular player object) Obviously this is less than ideal but it's a simple way to stick in the functionality you're looking for.

Related

How to optimize for loop - Python 3

My very first post, sorry if I made any mistakes!
I'm messing around the pygame library, and I'm extremely new to python in general. I have created 3 enemies classes and they work as intended, however, this is how I make them move (I call the move function stored inside the class).
I wonder if there is a more clean way to do things. I have many other enemies to code and this seems very repetitive to type, so it's a sign I'm doing something wrong.
I tried creating a "control list" where I list every enemy list there is and I try to access them through their index but it isn't working. I also tried to concatenate but I'm getting an error saying I can't concatenate list names, another error was that my list names turned into strings (yes, I tried using quotation marks). I'm sure this will be a simple fix, but I spent 3 days and I wrap my head around it. If it's possible to do so
The sample of my code so far - it is located in the main run loop of my game.
for giant in lst_enemy_giants:
giant.move()
else:
pass
for spider in lst_enemy_spiders:
spider.move()
else:
pass
for goblin in lst_enemy_goblin:
giant.move()
else:
pass
# The pattern the I want
for ENEMY in lst_enemy_ENEMY:
ENEMY.move()
# where ENEMY is any enemy list that can be stored somewhere
Just chain the iterators together.
from itertools import chain
for enemy in chain(lst_enemy_giants, lst_enemy_spiders, lst_enemy_goblin):
enemy.move()
This is a slightly nicer way of writing a nested loop like
for enemy_list in [lst_enemy_giants, lst_enemy_spiders, lst_enemy_goblin]:
for enemy in enemy_list:
enemy.move()
Unrelated, but I recommend keeping a single dict like
enemies = {'giants': [...], 'spiders': [...], 'goblins': [...]}
rather than three separate variables referencing separate lists. You can still use, for example, enemies['giants'] anywhere you would have used lst_enemy_giants, but now you can write
for enemy in chain(*enemies.values()):
enemy.move()

How do I detect pygame collisions?

I'm currently developing a small game with pygame and I'm having a hard time figuring out a way to check for collisions. I've found this question, but I can't use the pygame.sprite.spritecollide(player, wall_group, True) because my called player isn't a 'sprite', it's a class that I've created (that uses the functionality of normal shapes (https://www.pygame.org/docs/ref/draw.html)).
If anyone could figure a way that I can detect collisions and explain to me shortly about the difference between 'sprite' and just a normal shape like circle/rectangle I would appreciate it.
To use pygame's collition detection funcions (like pygame.sprite.spritecollide), your class does not need to be a subclass of pygame's Sprite.
Thanks to python's duck typing, the actual class does not matter, as long as your class behaves like a Sprite. In this context, it just means that your class should have a rect attribute, and it should be a Rect (again, technically, it does not need to be a Rect, only "look like" one).
Given a simple class like this:
>>> class Foo():
... def __init__(self):
... self.rect=pygame.rect.Rect(100, 100, 100, 100)
we can use pygame.sprite.spritecollide like this:
>>> f=Foo()
>>> g=Foo()
>>> pygame.sprite.spritecollide(f, [g], False)
[<__main__.Foo instance at 0x0000000003C6DF48>]
Also see how the second argument isn't a Group, but a simple List, but python does not care, since the only thing that matters in this case is that you can iterate over the object. If you would pass True as the third argument, this would fail, since spritecollide would try to call sprites() and the second argument and kill() on the elements inside.
Likewise, if you want to e.g. use pixel perfect collision detection, you need a mask attribute etc. So you should use the Sprite class anyway since it offers some more stuff like managing groups. Also, everytime you want to store a position or a size, consider using pygame's Rect class, since it's quite powerfull and it's used/expected in a lot of pygame functions.
tl;dr: Use pygame's Sprite class. There's probably no good reason for you to not do it, and a bunch of good reason to actually use it.

"For" loop Python code - does this look right/acceptable?

I would like to create a "for" loop (in Python 2). I have a list of obstacles and for each obstacle, if they are true (i.e. exist and appear in the list) I would like to append them to a list called "tests" and call a function called "obstacle_detection" (which deals with what happens when an obstacle is detected) (and I use "tests" later). This is part of a much larger program and I can't quite tell whether it's working, so I was wondering if anyone would be able to tell me if it makes sense? Or advise me of a better way there might be of doing this?
obstacles = [obstacle, obstacle1, obstacle2]
tests = []
counter = 0
for obstacle in obstacles:
tests.append(0)
tests[counter] = obstacle_detection(obstacle, pos)
counter = counter + 1
Your code possibly makes sense, depending on how you define obstacles and obstacle_detection.
As it is, you could write your code this way :
tests = [obstacle_detection(obstacle, pos) for obstacle in obstacles]
It creates a new list automatically, with the same length as obstacles and filled with obstacle_detection values for each obstacle.

python collision detection resolution circular dependencies

I'm working on a simple game in python (which I'm fairly new to as a language) using pygame and it seems as though python really hates circular dependencies (although I'm aware there are ways around this).
Generally for collision detection, I would have a callback function that is called, once a collision is detected, for each object involved in the collision. The problem is that in doing so, each object involved in the collision would need to know about the other in order to resolve the collision in the correct way, thus resulting in a circular dependency which I would prefer to avoid (see below).
Here is the Enemy.py module:
from Player include * #dependency on player
class Enemy():
def handle_collision(other_object):
if isinstance(other_object,Player) #this check requires the Enemy class to know about Player
Here is the Player.py module:
from enemy include * #dependency on enemy
class Player():
def handle_collision(other_object):
if isinstance(other_object,Wall):
#do what we need to do to resolve a wall collision
elif isinstance(other_object,Enemy): #this check requires that we include the Enemy class
#do what we need to do to resolve an enemy collision
Any suggestions or insight into how this is generally handled would be great.
Cyclic dependencies like these, where the module player.py imports the module enemy.py and vice versa are indeed rather tricky in Python. But there are (at least) two ways to work around those:
First, you do not need to import a module to use classes from that module. Even without importing the enemy.py module, you can use an instance of the Enemy class, e.g. after it has been passed to the handle_collision method as a parameter by some other module. Then, you could work around your problem by checking e.g. for other_object.__class__.__name__ == 'Enemy'.
This works, but it is not very nice, and will cause problems with, e.g., subclasses of Enemy.
Second, you do not have to put each class in it's own module/file, as it is common in, e.g., Java. In Python, it is perfectly normal and good practice to put many related classes in one and the same module. (One of the reasons why cyclic dependencies between modules are discouraged in Python is because needing them is considered a sign of bad system design.)
So my advice would be to put all of your "entity" classes into the same module, e.g. entities.py
class Entity:
def handle_collision(self, other_object):
pass
class Player(Entity):
def handle_collision(self, other_object):
if isinstance(other_object, Enemy):
# do stuff
class Enemy(Entity):
def handle_collision(self, other_object):
if isinstance(other_object, Player):
# do other stuff
Note that circular imports are in fact possible in Python, but should be used with care. For more about this, you can take a look at these two related posts.
You can generally eliminate circular dependency errors by moving the import from the module-level into a function or method where you actually need it.
In Player.py, try moving from enemy include * (which should be IMPORT, not INCLUDE) to be within your handle_collision method:
def handle_collision(other_object):
from enemy import Enemy
if isinstance(other_object,Wall):
#do what we need to do to resolve a wall collision
pass
elif isinstance(other_object,Enemy):
#this check requires that we include the Enemy class
pass
#do what we need to do to resolve an enemy collision
Also you should try to avoid importing * as it makes it difficult to see where your various imported names come from.

Chess negamax function

Hi!
I'm trying to write a negamax search algorithm for my chess engine, but i can't seem to get it working. I'm using wikipedias pseudocode as an example, but somehow it doesn't produce the expected results. When i run it with a ply of 2, it changes my board data structure, although it shouldn't. After the function is finished running with ply 2, all of the white's (or black's. depends what player calls the function.) pawns are moved 2 spaces forward from starting position.
My make and unmake move functions are working perfectly , as i tested them with a non-recursive function that searches up to 5-ply. Then, it worked perfectly. There must be something wrong with my negamax implementation.
Thank you very much for your help!
def negaMax(self, board, rules, ply, player):
""" Implements a minimax algorithm. """
if ply == 0:
return self.positionEvaluation()
self.max_eval = float('-infinity')
self.move_list = board.generateMoves(rules, player)
for self.move in self.move_list:
board.makeMove(self.move, player)
self.eval = -self.negaMax(board, rules, ply - 1, board.getOtherPlayer(player))
board.unmakeMove(self.move, player)
if self.eval > self.max_eval:
self.max_eval = self.eval
return self.max_eval
The main issue here is I believe the usage of object variables instead of local variable.
self.move is an object variable, every time you change it - every level of the recursion "sees" the change, which is usually a bad thing for recursive algorithms.
Recursive algorithms should be self contained, and do minimal if any change on the calling environment - it makes it much easier to walk over the flow of the algorithm.
The two main issues I see in this code are:
self.move should be a local variable (declare it as move). When you later do: board.unmakeMove(self.move, player) - I suspect that the board is undoing a different move, which was set deeper in the recursion tree, and not the one you intended. Using a local variable will eliminate this undesired behavior.
Each level of the recursive call is setting self.max_eval = float('-infinity') - so you constantly change it, though it is probably not what you want to do.
The solution should be something like that:
def negaMax(self, board, rules, ply, player):
""" Implements a minimax algorithm. """
if ply == 0:
return self.positionEvaluation()
max_eval = float('-infinity')
move_list = board.generateMoves(rules, player)
for move in move_list:
board.makeMove(move, player)
currentEval = -self.negaMax(board, rules, ply - 1, board.getOtherPlayer(player))
board.unmakeMove(move, player)
if currentEval > max_eval:
max_eval = currentEval
return max_eval
I am not 100% certain it will indeed solve everything in the code (but it will solve some of it) but I am 100% certain avoiding object variables will make your code much easier to understand and debug.

Categories