Pygame: Showing sprite without a group - python

I have two sprites in a class for easier control (specifically: tank turret and suspension). If I try to launch program it works without any errors, but it doesn’t show anything. I also tried to put both of sprites in group in class, but it threw error
TypeError: draw() missing 1 required positional argument: 'surface'
The code is:
class Bokstelis(pygame.sprite.Sprite):
def __init__(self,atvaizdas,centerx,centery,sukgreitis):
pygame.sprite.Sprite.__init__(self)
self.nuotr=pygame.image.load(atvaizdas)
self.image=self.nuotr
self.rect=self.image.get_rect()
self.rect.centerx=centerx
self.rect.centery=centery
self.sukgreitis=sukgreitis
self.kryptis=0
def update(self):
mouseX, mouseY=pygame.mouse.get_pos()
self.angle = math.degrees(math.atan2(mouseY - self.rect.centery, mouseX - self.rect.centerx))
orig_rect=self.rect
if self.angle - self.kryptis <self.sukgreitis:
self.image=pygame.transform.rotate(self.nuotr,-(self.sukgreitis+self.kryptis))
elif self.angle - self.kryptis >self.sukgreitis:
self.image=pygame.transform.rotate(self.nuotr,self.sukgreitis+self.kryptis)
else:
self.image=pygame.transform.rotate(self.nuotr,-angle)
self.rect=self.image.get_rect()
self.rect.center=orig_rect.center
self.kryptis=self.angle
class Pagrindas(pygame.sprite.Sprite):
def __init__(self,atvaizdas,centerx,centery,sukgreitis):
pygame.sprite.Sprite.__init__(self)
self.nuotr=pygame.image.load(atvaizdas)
self.image=self.nuotr
self.rect=self.image.get_rect()
self.rect.centerx=centerx
self.rect.centery=centery
self.sukgreitis=-sukgreitis
self.kryptis=0
def suktis(self):
orig_rect=self.rect
self.image=pygame.transform.rotate(self.nuotr,-sukgreitis)
self.rect=self.image.get_rect()
self.rect.center=orig_rect.center
self.kryptis-=kryptis
class Tankas:
def __init__(self,centerx,centery,bokstelis,pagrindas,maxjudgreit,galingumas,svoris):
self.bokstelis=bokstelis
self.pagrindas=pagrindas
self.centerx=centerx
self.centery=centery
self.bokstelis.rect.center=(self.centerx,self.centery)
self.pagrindas.rect.center=(self.centerx,self.centery)
self.grup=pygame.sprite.Group(self.bokstelis,self.pagrindas)
self.maxjudgreit=maxjudgreit
self.galing=galingumas
self.svoris=svoris
self.judejimas=0
self.kryptis=self.pagrindas.kryptis
self.greit=False
self.maxdabgreit=72
def update(self):
self.centerx,selfcentery=self.judejimas * math.cos(math.radians(self.kryptis)), self.judejimas * math.sin(math.radians(self.kryptis))
self.bokstelis.rect.center=(self.centerx,self.centery)
self.pagrindas.rect.center=(self.centerx,self.centery)
self.bokstelis.update()
self.pagrindas.update()
if self.maxdabgreit < self.judejimas:
selfjudėjimas-=self.galing/self.svoris
elif self.greit:
self.judejimas=self.judejimasself.galing/self.svoris
For adding class I added 'self.grup(self.bokstelis,self.pagrindas)' in __init__, and changed self.bokstelis.update() and self.pagrindas.update() with
self.grup.clear()
self.grup.update()
self.grup.draw()
Full eror mesage:
Traceback (most recent call last):
File "C:\Users\Kiela\Dropbox\IK8\IK3\World of Tankz.py", line 76, in <module>
tankas.grup.draw()
TypeError: draw() missing 1 required positional argument: 'surface'
What should I do for the displaying of my tank without disabling of my class?

pygame.sprite.Group.draw() requires a non optional argument 'surface'.
If you're bliting straight to the screen (screen = pygame.display.set_mode()) you do: self.grup.draw(screen)
Your other alternative is to make a surface and blit that to the screen:
screen = pygame.display.set_mode((0, 0)) # Create the main window
#Create the sprites and groups etc.
...
surface = pygame.Surface(screen.get_size)
self.grup.draw(surface)
screen.blit(surface)
pygame.display.flip()
but this is the more complicated of the two.
If you want it straight from the docs it can be found here: https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Group.draw

Related

Python set class variable after calling

I'm making a game using the pygame module and I have a player class:
class Player(pygame.sprite.Sprite):
def __init__(self, name, position, axsis, movment, idle, walk = None, jump = None):
pygame.sprite.Sprite.__init__(self)
self.name = name
self.idle = idle
self.walk = walk
self.jump = jump
self.image = self.idle[0]
self.movment = movment
self.left, self.right = axsis
self.pos = vec(position[0],position[1])
I am adding my characters using json data type and trying to add animations after calling the class but i can't do it
Sample code
class Game():
def __init__(self,json_file):
self.player_attribute = json_file
def character(self):
self.npc = []
for i in self.player_attribute:
self.npc.append(Player(i['name'],
i['position'],
i['axsis'],
i['movment']))
self.animation()
return self.npc
def add_animation(self):
for i in self.npc:
i.idle = "images\ghost.png"
def main_loop()
self.character
when i try this i get an error
self.image = self.idle[0]
TypeError: init() missing 1 required positional argument: 'idle'
how can i add the variables of the class after calling the class
It is not clear what the 'idle' parameter is supposed to represent in your code. However, the reason for the exception is that you are not passing any argument for 'idle' when constructing the Player object. You need something like:
self.npc.append(Player(i['name'],
i['position'],
i['axsis'],
i['movment'],
i['idle']))
You can either do that or alternatively you can pass a default argument to the Player constructor so that, when initializing you do not need to explicitly pass idle:
class Player(pygame.sprite.Sprite):
def __init__(self, name, position, axsis, movment, idle=[1], walk = None, jump = None):
You can modify its content at a later time, however I suggest you are careful what you instantiate that object attribute as, because it might come bite you back later (type error or value error).
If it were me, I would move this out of init, or not build the object until all values and their types are known (see Builder Design Pattern).
Hope this helped :) Cheers!

TypeError: argument 1 must be pygame.Surface, not type

I'm making a submarine game in python, but when I try to run it, the interpreter gives me very strange error:
"TypeError: argument 1 must be pygame.Surface, not type."
I tried to search the web for my answer, but it seems like this isn't very usual error. I also tried to find error by myself, but everything seemed fine to me. Here 's part of the code that I think error is in:
mina = pygame.image.load('mina.png')
class mina():
def __init__(self, x , y):
self.x = x
self.y = y
self.eksplozija = False
def naris(self):
screen.blit(mina, (self.x, self.y))
igralec = podmornica(150, 300, 10)
eksploziv = mina(700, 350)
metki = []
clock = pygame.time.Clock()
def grafika():
clock.tick(60)
screen.blit(ozadje, (0,0))
igralec.naris()
#line, that doesn't work:
eksploziv.naris()
for metek in metki:
metek.naris(screen)
pygame.display.flip()
The variable mina and the class mina have the same name. The class mina shadows the variable mina. You need to rename one or the other. I recommend to rename the calss mina to Mina, since Python classes use the CapWords convention (PEP 8 -- Style Guide for Python Code):
class mina():
class Mina():
eksploziv = mina(700, 350)
eksploziv = Mina(700, 350)

Issues with mask multiple of the same identical mob in pygame

as discussed in the title I am having issues with masking identical images.
#initalising the masks
Invader1= pygame.image.load('Space_invaders_character_1_1.png').convert_alpha()
Invader1= pygame.transform.scale(Invader11, (40,30))
Invader1_mask = pygame.mask.from_surface(Invader11)
Invader1_mask= Invader11_mask.scale((70,40))
Invader2= pygame.image.load('Space_invaders_character_2_1.png').convert_alpha()
Invader2= pygame.transform.scale(Invader21, (40,30))
Invader2_mask = pygame.mask.from_surface(Invader21)
Invader2_mask= Invader11_mask.scale((70,40))
Invader3= pygame.image.load('Space_invaders_character_3_1.png').convert_alpha()
Invader3= pygame.transform.scale(Invader31, (40,30))
Invader3_mask = pygame.mask.from_surface(Invader31)
Invader3_mask= Invader11_mask.scale((70,40))
#drawing characters
def drawEnemies (invX,invY):
for num in range (1,11):
invX = invX + 50
gameDisplay.blit(Invader32, (invX,invY))
gameDisplay.blit(Invader32, (invX,invY-50))
gameDisplay.blit(Invader22, (invX,invY-100))
gameDisplay.blit(Invader22, (invX,invY-150))
gameDisplay.blit(Invader12, (invX, invY -200))
while lives > 0:
offset = (bulletX -invX, bulletY - invY)
result = Invader11_mask.overlap(bullet_mask, offset)
Of course this isn't all my code, however, I hope you see what I am attempting to do. In essence I am attempting to loop to create a specific Invader (yes from space invaders), however, the masks are either not being created with the other invaders or aren't moving. Can someone please help me?
Thanks.
The meaningful answer to your problem is to stop what your doing right now and start using the Sprite and Group classes together with the collide_mask function.
You don't want to create several global variables for each thingy in your game. You want instances of classes (you usually use Sprite), and add them to a list (usually a Group).
So, create a class for your invaders that inherits from Sprite and give them a mask attribue, something like this:
class Invader(pygame.spriteSprite):
def __init__(self, image, pos):
super().__init__()
self.image = image
self.rect = image.get_rect(topleft=pos)
self.mask = pygame.mask.from_surface(image)
def update(self):
pass # handle movement
Create a Group for your bullets and one for your invaders, then you can check the collision with:
pygame.sprite.groupcollide(bullets, invaders, True, True, pygame.sprite.collide_mask)

Python Inheritance Issue

I have a class that is inheriting from another class, and I get the issue:
Traceback (most recent call last):
File "main.py", line 45, in <module>
class Player(Entity):
File "main.py", line 53, in Player
self.image = pygame.image.load('sam_stand.png')
NameError: name 'self' is not defined
These are the classes:
class RigidBody(object):
def __init__(self, (x, y), size, mass=1):
self.x = x
self.y = y
self.size = size
self.mass = mass
self.thickness = 0
self.angle = 0
self.drag = 1
self.elasticity = 0.9
class Player(Entity):
"""Player class. Provides all player variables and methods"""
def __init__(self):
RigidBody.__init__(self)
self.grounded = True
self.direction = "Right"
self.axis = "Down"
self.jump_counter = 0
self.image = pygame.image.load('sam_stand.png')
How come self is recognized for all the other attributes for the Player, except for self.image? If I change it to image = pygame.image.load('sam_stand.png') the problem goes away.
You are mixing tabs and spaces. When looking at your first revision source I see this:
Your method body is indented with tabs, which Python expands to 8 spaces. The last line, however, is indented with spaces only. You have your editor set to 4 spaces per tab, so you cannot see this mistake.
As a result, the self.image line falls outside the __init__ method. It is part of the class definition instead.
You really want to configure your editor to indent with spaces only.
Run your code with python -tt scriptname.py and fix all the errors that reports. Then run the tabs-to-spaces feature in your text editor (converting to 4 spaces) and then configure it to use spaces for indentation (automatically inserting 4 spaces when you use the tab key).
Using spaces for indentation is recommended by the Python styleguide for a reason, after all.

collision detection error:AttributeError: type object 'Ship_laser' has no attribute 'sprites'

I am trying to write a game using a model, but i get the error:
"File "C:\Python27\lib\site-packages\pygame\sprite.py", line 1514, in spritecollide
for s in group.sprites():AttributeError: type object 'Ship_laser' has no attribute 'sprites'"
when running the script.If i dont call my collision function the script runs, so in that function is the mistake,but i dont understand where's the mistake.Here is the code of the function:
def collisions():
for enemy_ship in classes.Enemy_ship.List:
enemy_laser = pygame.sprite.spritecollide(enemy_ship, classes.Ship_laser, True)
if len(enemy_laser) > 0:
for hit in enemy_laser:
enemy_ship.health -= 25
for laser in classes.Ship_laser.List:
if pygame.sprite.spritecollide(laser, enemy_ship, True):
laser.destroy()
If it's needed i am posting the the Ship_laser class from my classes.py file
class Ship_laser(pygame.sprite.Sprite):
allsprites = pygame.sprite.Group()
def __init__(self, x, y, image_string):
pygame.sprite.Sprite.__init__(self)
Ship_laser.allsprites.add(self)
self.image = pygame.image.load(image_string)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.velx, self.vely = 0, 0
#staticmethod
def laser_movement(SCREENWIDTH, SCREENHEIGHT):
for laser in Ship_laser.List:
laser.rect.x += laser.velx
laser.rect.y += laser.vely
def destroy(self):
Ship_laser.List.remove(self)
del self
Considering that the Laser.ship class it's inheriting the pygame.sprite.Sprite class i dont understand the error.This is my first game.Please help
I can't say I am an expert with pygame, nor do I fully understand how you have built your classes. When I hear ship laser, I think of a single instance that belongs to a ship, yet in your class you define "allsprites" which is mutable type defined to a class instance (shared by all members of the class).
But given this, allsprites will be the same mutable object shared among ever ship_laser, almost like the yellowpages of your class. When you call pygame.sprite.spritecollide (based on pygame docs) it is looking for the sprite.Group and hence, you should pass it the group lookup (the yellowpages aka allsprites) rather than the reference to the class. That should sort your issues. So, here is your code change:
enemy_laser = pygame.sprite.spritecollide(enemy_ship, classes.Ship_laser, True)
to
enemy_laser = pygame.sprite.spritecollide(enemy_ship, classes.Ship_laser.allsprites, True)

Categories

Resources