How do I detect pygame collisions? - python

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.

Related

Character class VS. Character list

On nearly all of the example programs for pygame, characters are instantiated as classes with some code like this one:
class Character(object):
def__init__(self,image,stuff):
self.image = image
self.stuff = stuff[:]
bob = Character(image,stuff)
I am wondering what the benefit of using a class is over using just a plain list. I could instead of using class instantiation just create a list like this:
bob = [image,stuff[:]]
I was wondering if the reason that people use classes is to have functions that interact directly with the character and are just defined as a part of the class rather than as a separate function that can be used on the character.
Thank you!
Generally, I'd say it's more clear. With the list, you'll end up wondering "what was at index 0? what was at index 1?" and so forth. Then you'd have to trace back through the code to find where bob was defined to make sure.
Additionally, if you create other characters throughout the code, you have to create them all the same way. With the class, you can easily search the codebase for character creations and update it (e.g. if you want to add another property to characters) and if you miss any, python will throw an Exception so you know where to fix it. With the list, it's going to be really hard to find and python won't tell you if you miss any -- You'll get a funky IndexError that you need to trace back to the root cause which is more work.
When using a class you might be able to inherit from other class and create methods, which doesn't apply to lists. But if you know that you will only be using static values like your class Character does, you might check out namedtuple. Here's a simple example how to use it:
from collections import namedtuple
Character = namedtuple('Character', 'image stuff')
bob = Character(image, stuff)
Why use a class Bob over a list bob in this simple case:
Easy access to an attribute. It's simpler to remember Bob.image than bob[0]. The longer the list is, the harder it gets.
Code readability. I have no idea what the line bob[7]=bob[3]+bob[6] does. With a class, the same line becomesBob.armor=Bob.shield+Bob.helmet, and I know what it does.
Organization. If some functions are only meant to be use on characters, it's practical to have them declared just after the attributes. A class forces you to have everything related to characters at the same place.
Instead of a list though, you could use a dictionary:
bob = {"image":image, "stuff":stuff[:], ...}
bob["armor"]=bob["shield"]+bob["helmet"]
As with a class, you have an easy access to attributes and code is readable.

Sprite Values Must Move

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.

Composition: Should I access the "inner object's" methods directly?

I am relatively new to OOP, and definitely still learning. I would like to know what is the best practice when dealing with two classes such as this:
(I have reverse engineered the statistics engine of an old computer game, but I guess the subject does not matter to my question)
class Step(object):
def __init__(self):
self.input = 'G'
...more attributes...
def reset_input(self):
''' Reset input to None. '''
self.input = None
print '* Input reset.'
... more methods ...
Then I have the Player class, which is the main object to control (at least in my design):
class Player(object):
''' Represents a player. Accepts initial stats.'''
def __init__(self, step= 250, off= 13, dng= 50000, dist= 128, d_inc= 113):
self.route = []
self.step = Step(step=step, off=off, dng=dng, dist=dist, d_inc=d_inc)
self.original = copy.copy(self.step)
As you can see, Player contains a Step object, which represents the next Step.
I have found that I sometimes want to access a method from that Step class.
In this case, is it better to add a wrapper to Player, such as:
(If I want to access reset_input()):
class Player(object):
...
def reset_input(self):
self.step.reset_input()
Then for Player to reset the input value:
p = Player()
p.reset_input()
Or would it be better practice to access the reset_input() directly with:
p = Player()
p.step.reset_input()
It seems adding the wrapper is just duplicating code. It's also annoying as I need access to quite a few of Step's methods.
So, when using composition (I think it is the correct term), is it good practice to directly access the 'inner' objects methods?
I believe you should apply an additional layer of abstraction in OOP if:
you foresee yourself updating the code later; and
the code will be used in multiple places.
In this case, let's say you go with this method:
def reset_input(self):
self.step.reset_input()
and then you call it in multiple places in your code. Later on, you decide that you want to do action x() before all your calls to reset_input, pass in optional parameter y to reset_input, and do action z() after that. Then it's trivial to update the method as follows:
def reset_input(self):
self.x()
self.step.reset_input(self.y)
self.z()
And the code will be changed everywhere with just a few keystrokes. Imagine the nightmare you'd have on your hands if you had to update all the calls in multiple places because you weren't using a wrapper function.
You should apply a wrapper if you actually foresee yourself using the wrapper to apply changes to your code. This will make your code easier to maintain. As stated in the comments, this concept is known as encapsulation; it allows you to use an interface that hides implementation details, so that you can easily update the implementation at any time and it will change the code universally in a very simple way.
It's always a tradeoff. Look at the Law of Demeter. It describes your situation and also pros and cons of different solutions.

Sikulli: Passing Regions to setROI() function

Lets say that in Sikulli I create a region called myRegion and pass it to setROI().Would using find(pictureIWantToFind) be just as fast as if I didn't use setROI() and instead called find(myRegion.inside().exists(pictureIWantToFind))?
Also, setROI() will continue to use that region of interest until you tell it otherwise such as with setROI(SCREEN)?
As you have it stated, yes, I believe that using SetROI() would be slightly faster than find(myRegion.inside().exists(PictureYouWantToFind)--just marginally.
-BUT-
Because the find() operation is a method of the Region class, instead of calling find(myRegion.inside().exists(myPic)), you can accomplish the same thing a little more simply this way: myRegion.find(myPic)
The default ROI is the whole screen referenced with the reserve word "SCREEN". So, find(myPic) is the same as SCREEN.find(myPic). Passing myRegion to setROI(), as in setROI(myRegion), redefines SCREEN so that now SCREEN = myRegion. If you choose to use setROI() be aware--all following Region operations (such as wait() or exists()) would act on myRegion and not on the whole screen, until you redefine it as such, as per this answer in the Sikuli forums.
In sum, myRegion.find(myPic) will allow you to search the smaller ROI, without renaming SCREEN.

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.

Categories