Create sprites in class and get collision

Viewed 53

Hi i'm learning python by creating a game. I use pygame to create the game where two players fight in knight tournment. The idea of ​​game is simple, from two sides players need to press gallop key and operating the spear to hit eachother. I have class with move of the block and i want to add the spear inside the class but i can't draw spear ...

import pygame
from sys import exit

#Class

class Knight(pygame.sprite.Sprite):
    def __init__(self,pos_x, pos_y, width, height, color):
        super().__init__()

        #Knight image
        self.image= pygame.Surface([width, height])
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.rect.midbottom = [pos_x, pos_y]

        #Knight spear
        self.image_spear = pygame.Surface((200, 200))
        self.image_spear.set_colorkey((0, 0, 0))
        self.rect_spear = self.image_spear.get_rect(center=(pos_x, pos_y))
        self.angle_spear = 0
    def player_input(self):
        keys = pygame.key.get_pressed()
        #Moving knight
        if keys[pygame.K_SPACE]:
            self.move = 1
            self.rect.x +=self.move
        #Moving spear
        if keys[pygame.K_w]:
            self.angle_spear += 1
        elif keys[pygame.K_s]:
            self.angle_spear -= 1

    def update(self):
        #Update moving knight
        self.player_input()
        #Update spear
        self.angle_spear = self.angle_spear
        self.image_spear.fill(0)
        pygame.draw.line(self.image_spear, (255, 255, 100), (self.pos_x, 30+self.pos_y), (100 + self.pos_x, self.poy+self.angle), 5)
        self.mask = pygame.mask.from_surface(self.image)

class Ground(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image= pygame.Surface([800, 100])
        self.image.fill('white')
        self.rect = self.image.get_rect()
        self.rect.bottomleft = [0, 400]



#screen
pygame.init()
screen = pygame.display.set_mode((800,400))
pygame.display.set_caption("Geometry_War")
clock = pygame.time.Clock()

#screen view
#ground = pygame.Rect(0, 300, 800, 200)
#ground_screen=pygame.draw.rect(screen, 'white', ground)

#start values
game_active = True
Knight1 = Knight(100, 300, 60, 60,(255,125,125))
Knight2 = Knight(700, 300, 60, 60,(255,000,125))
Ground = Ground()
#Sprite group
sprite_group=pygame.sprite.Group()
sprite_group.add(Knight1, Knight2,Ground)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
                pygame.quit()
                exit()

    if game_active:

        screen.fill(0)
        sprite_group.update()
        sprite_group.draw(screen)



    pygame.display.flip()
    pygame.display.update()
    clock.tick(60)

The idea: enter image description here

In next step i want to get point of collision and calculate the power of hit for each player(fast*point =score). Better score wins. What i'm doing wrong?

1 Answers

You're almost there. There's a few typos in the code (as commented by Layne Bernardo) that are causing the immediate issues. Fix them, and it will start to work.

animation

One other issue is the handling of user-input inside the Knight sprite class. I think doing this here is a mistake. The sprite class exists to hold the position and dimensions of an on-screen bitmap, not process user input. This should be moved outside of the class, probably to the main loop. If you still want it separate, put it inside a function, but not a sprite member-function.

Below I fixed up the code to the point where it would work, then got carried away playing with lance-angles... eventually re-working a lot of the Knight class.

import pygame
import math
from sys import exit

#Class

class Knight(pygame.sprite.Sprite):
    def __init__(self,pos_x, pos_y, width, height, color):
        super().__init__()
        #Knight image
        self.image= pygame.Surface([width*2, height*2])   # note: twice width to leave room for rotating spear
        self.rect = self.image.get_rect()
        self.rect.midbottom = ( pos_x, pos_y )
        self.base_color  = color
        #Knight spear
        self.spear_color  = ( 255, 255, 100 )
        self.spear_length = 50  # pixels
        self.spear_angle  = 180
        self.makeSpriteImage()  # get initial rendering
        # Movement
        self.speed = 0
        self.direction = 1  # 1=right, -1=left

    def update( self ):
        """ Move the horsey ... if we have any speed """
        self.rect.x += self.speed * self.direction

    def makeSpriteImage( self ):
        """ Draw the Knight's representation into the sprite image.
            Done whenever the image needs to change """
        self.image.fill( ( 0, 0, 0, 0, ) ) # transparent
        pygame.draw.rect( self.image, self.base_color, pygame.Rect( 0,self.rect.height//2, self.rect.width//2, self.rect.height//2 ) );  # quarter-fill bottom-left corner
        spear_base_x  = self.rect.width  // 4  # width is double
        spear_base_y  = self.rect.width // 2 + self.rect.height // 4
        spear_point_x = spear_base_x + ( self.spear_length * math.sin( math.radians( self.spear_angle ) ) ) 
        spear_point_y = spear_base_y + ( self.spear_length * math.cos( math.radians( self.spear_angle ) ) )
        pygame.draw.line( self.image, self.spear_color, (spear_base_x, spear_base_y), (spear_point_x, spear_point_y), 2 )
        #print( "Line at %d degrees, from (%d,%d) to (%d,%d) length %d" % ( self.spear_angle, spear_base_x, spear_base_y, spear_point_x, spear_point_y, self.spear_length ) )
        self.mask = pygame.mask.from_surface(self.image)

    # Handle user-change to the sprite
    def accelerate( self, amount=2 ):
        self.speed += amount
    def decelerate( self, amount=2 ):
        self.speed += amount
    def turnAround( self ):
        self.direction = -self.direction  # flip directions

    def setSpearPosition( self, angle ):
        """ The user has adjusted the spear position, regenerate the Knight's image """
        self.spear_angle = angle
        self.spear_angle = max( 45, self.spear_angle )  # Keep spear angle sensible
        self.spear_angle = min( 180, self.spear_angle )
        self.makeSpriteImage()  # regenerate the bitmap

    def raiseSpear( self ):
        self.setSpearPosition( self.spear_angle + 3 )
    def lowerSpear( self ):
        self.setSpearPosition( self.spear_angle - 3 )


class Ground(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image= pygame.Surface([800, 100])
        self.image.fill('white')
        self.rect = self.image.get_rect()
        self.rect.bottomleft = [0, 400]



#screen
pygame.init()
screen = pygame.display.set_mode((800,400))
pygame.display.set_caption("Geometry_War")
clock = pygame.time.Clock()

#start values
game_active = True
Knight1 = Knight(100, 300, 60, 60,(255,125,125))
Knight2 = Knight(700, 300, 60, 60,(255,000,125))
Ground = Ground()
# Sprite group
background_group=pygame.sprite.Group()  # background group does not need to update
background_group.add(Ground)
knight_group=pygame.sprite.Group()
knight_group.add(Knight1, Knight2)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    # handle player input
    keys = pygame.key.get_pressed()
    #Moving knight
    if keys[pygame.K_SPACE]:
        Knight1.accelerate()
    if keys[pygame.K_BACKSPACE]:
        Knight1.decelerate()   # wooooah!

    #Moving spear
    if keys[pygame.K_w]:
        Knight1.raiseSpear()
    if keys[pygame.K_s]:
        Knight1.lowerSpear()

    # Paint the screen
    screen.fill(0)
    knight_group.update()
    knight_group.draw(screen)
    background_group.draw(screen)

    #pygame.display.flip()   # flip() or update(), not both
    pygame.display.update()
    clock.tick(60)
Related