PYGAME Sprite rect碰撞vs sprite碰撞 [英] PYGAME Sprite rect collision vs sprite collision

查看:82
本文介绍了PYGAME Sprite rect碰撞vs sprite碰撞的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个平台游戏,并在平台上来回传播一个斑点(异形)作为障碍物

对于碰撞,我遇到了一个问题,即我的外星精灵击打盒很大,一旦我的玩家进入瓷砖范围的0.75范围之内,他就会立即死亡.我希望点击框更小

当前我正在使用pygame.sprite.spritecollide在我的播放器和Blob之间发生碰撞

无论如何,我改变了这一点,无法修复点击框

有没有办法解决这个问题,我相信pygame.sprite.collide_rect或collide_rect_ratio可能有效,但我不知道如何使用该功能

有人可以解释一下我应该在代码中进行哪些更改以解决此问题(点击框)

TLDR;我想修复我的垃圾箱,您能简单地解释一下吗

这是碰撞的代码

 #检查与敌人的碰撞如果pygame.sprite.spritecollide(self,blob_group,False):game_over = -1game_over_fx.play() 

这是我的完整代码

  #import模块导入pygame从pygame.locals导入*从pygame导入混音器进口泡菜从os导入路径#initiliaze pygameepygame.mixer.pre_init(44100,-16,2,512)#音量控制mixer.init()pygame.init()#fps时钟= pygame.time.Clock()字体= pygame.font.SysFont('包豪斯93',70)font_score = pygame.font.SysFont('包豪斯93',30)#screen创建/全局变量screen_width = 800screen_height = 800tile_size = 40帧/秒= 60game_over = 0main_menu =真等级= 7max_levels = 7分数= 0屏幕= pygame.display.set_mode((screen_width,screen_height))pygame.display.set_caption('Crashlandingv6')#颜色白色=(255,255,255)红色=(255,15,15)蓝色=(0,0,200)#加载图片bg_img = pygame.image.load('img/background.jpg')bg_img = pygame.transform.scale(bg_img,(1000,1000))earth_img = pygame.image.load('img/earth.png')earth_img = pygame.transform.scale(earth_img,(100,100))rect = bg_img.get_rect()restart_img = pygame.image.load('img/restart_btn.png')start_img = pygame.image.load('img/start_btn.png')exit_img = pygame.image.load('img/exit_btn.png')#加载声音pygame.mixer.music.load('img/music.wav')pygame.mixer.music.play(-1,0.0,15000)coin_fx = pygame.mixer.Sound('img/coin.wav')coin_fx.set_volume(0.4)jump_fx = pygame.mixer.Sound('img/jump.wav')jump_fx.set_volume(0.4)game_over_fx = pygame.mixer.Sound('img/gameover.wav')game_over_fx.set_volume(0.5)定义draw_text(text,font,text_col,x,y):img = font.render(text,True,text_col)screen.blit(img,(x,y))#function重置级别def reset_level(级别):player.reset(100,screen_height-130)blob_group.empty()lava_group.empty()exit_group.empty()如果path.exists(f'level {level} _data'):pickle_in =打开(f'level {level} _data','rb')world_data = pickle.load(点刺)世界=世界(world_data)回归世界#create按钮类类Button():def __init __(self,x,y,image):self.image =图片self.rect = self.image.get_rect()self.rect.x = xself.rect.y = yself.clicked = Falsedef draw():行动=错误pos = pygame.mouse.get_pos()#检查按钮是否发生碰撞(如果点击了按钮,{action}如果self.rect.collidepoint(pos):如果pygame.mouse.get_pressed()[0] == 1并且self.clicked == False:行动=正确self.clicked =真如果pygame.mouse.get_pressed()[0] == 0:self.clicked = False#draw按钮显示screen.blit(self.image,self.rect)退货行动#播放器类别类Player():def __init __(self,x,y):self.reset(x,y)def更新(自我,游戏结束):dx = 0 #delta xdy = 0 #delta ywalk_cooldown = 4#速度col_thresh = 20如果game_over == 0:#如果游戏正在运行gameover = 0如果游戏结束gameover = -1#获取按键(控件)键= pygame.key.get_pressed()如果key [pygame.K_SPACE]和self.jumped == False:jump_fx.play()self.vel_y = -15self.jumped =真如果键[pygame.K_LEFT]:dx-= 5self.counter + = 1self.direction = -1如果键[pygame.K_RIGHT]:dx + = 5self.counter + = 1self.direction = 1如果key [pygame.K_LEFT] == False和key [pygame.K_RIGHT] == False:self.counter = 0self.index = 0如果self.direction == 1:self.image = self.images_right [self.index]如果self.direction == -1:self.image = self.images_left [self.index]#TO DO<在这里插入!#如果所有按钮都为假,则添加空闲播放器动画,将播放器设置为空闲#播放器动画如果self.counter>walk_cooldown:self.counter = 0self.index + = 1如果self.index> = len(self.images_right):self.index = 0如果self.direction == 1:self.image = self.images_right [self.index]如果self.direction == -1:self.image = self.images_left [self.index]#增加重力self.vel_y + = 1如果self.vel_y>10:self.vel_y = 10dy + = self.vel_y#检查碰撞用于world.tile_list中的图块:#x方向碰撞如果tile [1] .colliderect(self.rect.x + dx,self.rect.y,self.width,self.height):dx = 0#y方向碰撞如果tile [1] .colliderect(self.rect.x,self.rect.y + dy,self.width,self.height):#检查是否在地下(跳跃)如果self.vel_y <0:dy = tile [1] .bottom-self.rect.topself.vel_y = 0#检查地面是否在上方(下落)elif self.vel_y> = 0:dy = tile [1] .top-self.rect.bottomself.jumped = False#检查与敌人的碰撞如果pygame.sprite.spritecollide(self,blob_group,False):game_over = -1game_over_fx.play()#检查是否与熔岩发生碰撞如果pygame.sprite.spritecollide(self,lava_group,False):game_over = -1#检查与出口的碰撞如果pygame.sprite.spritecollide(self,exit_group,False):game_over = 1#平台碰撞对于platform_group中的平台:#检查x碰撞如果platform.rect.colliderect(self.rect.x + dx,self.rect.y,self.width,self.height):dx = 0#y碰撞如果platform.rect.colliderect(self.rect.x,self.rect.y + dy,self.width,self.height):#检查是否低于平台如果abs((self.rect.top + dy)-platform.rect.bottom)<col_thresh:self.vel_y = 0dy = platform.rect.bottom-self.rect.top#检查是否在平台之上elif abs((self.rect.bottom + dy)-platform.rect.top)<col_thresh:self.rect.bottom = platform.rect.top-1self.in_air =假dy = 0#横向移动平台如果platform.move_x!= 0:self.rect.x + = platform.move_direction#if gameover(召回gameover = -1 gamerunning = 0)elif game_over == -1:self.image = self.dead_imagedraw_text('GAME OVER!',font,red,(screen_width//2)-200,screen_height//2)如果self.rect.y>200:self.rect.y-= 5#update玩家坐标self.rect.x + = dxself.rect.y + = dy#将播放器绘制到屏幕上screen.blit(self.image,self.rect)#for rect取消注释#pygame.draw.rect(screen,(255,255,255),self.rect,2)返回game_overdef reset(self,x,y):重置按钮下的#Player类,创建播放器类时,出于效率目的而从reset调用信息(而不是键入两次)self.images_right = []self.images_left = []self.index = 0self.counter = 0对于范围(1,7)中的num:img_right = pygame.image.load(f'img/guy {num} .png')img_right = pygame.transform.scale(img_right,(40,80))img_left = pygame.transform.flip(img_right,True,False)#在x轴{true}而非y轴{false}上翻转右图像self.images_right.append(img_right)self.images_left.append(img_left)self.dead_image = pygame.image.load('img/ghost.png')self.image = self.images_right [self.index]self.rect = self.image.get_rect()self.rect.x = xself.rect.y = yself.width = self.image.get_width()self.height = self.image.get_height()self.vel_y = 0self.jumped = Falseself.direction = 0#瓷砖类别World()类:def __init __(self,data):self.tile_list = []#加载图片dirt_img = pygame.image.load('img/dirt.png')moonrock_img = pygame.image.load('img/moonrock.png')#游戏地图row_count = 0用于数据行:col_count = 0对于行中的图块:如果tile == 1:#替换为灰尘img = pygame.transform.scale(dirt_img,(tile_size,tile_size))img_rect = img.get_rect()img_rect.x = col_count * tile_sizeimg_rect.y =行数* tile_size瓦=(img,img_rect)self.tile_list.append(tile)如果tile == 2:#用Moonrock替换img = pygame.transform.scale(moonrock_img,(tile_size,tile_size))img_rect = img.get_rect()img_rect.x = col_count * tile_sizeimg_rect.y =行数* tile_sizetile =(img,img_rect)self.tile_list.append(tile)如果tile == 3:#替换为外星人blob =敌人(col_count * tile_size,row_count * tile_size + 10)blob_group.add(blob)如果tile == 4:平台=平台(col_count * tile_size,row_count * tile_size,1,0)#y方向platform_group.add(平台)如果tile == 5:平台=平台(col_count * tile_size,row_count * tile_size,0,1)platform_group.add(平台)如果tile == 6:#替换为酸熔岩=熔岩(col_count * tile_size,row_count * tile_size +(tile_size//2))lava_group.add(熔岩)如果tile == 7:coin = Coin(col_count * tile_size +(tile_size//2),row_count * tile_size +(tile_size//2))coin_group.add(硬币)如果tile == 8:退出=退出(col_count * tile_size,row_count * tile_size-(tile_size//2))exit_group.add(退出)col_count + = 1row_count + = 1def draw(self):#将图块绘制到屏幕上用于self.tile_list中的图块:screen.blit(tile [0],tile [1])#for矩形轮廓取消注释#pygame.draw.rect(screen,(255,255,255),tile [1],1)#ENEMY SPRITE类敌人类(pygame.sprite.Sprite):def __init __(self,x,y):pygame.sprite.Sprite .__ init __(自己)self.image = pygame.image.load('img/blob.png')self.image = pygame.transform.scale(self.image,(65,35))self.rect = self.image.get_rect()self.rect.x = xself.rect.y = yself.move_direction = 1self.move_counter = 0def update(self):#update敌人(动作)self.rect.x + = self.move_directionself.move_counter + = 1如果abs(self.move_counter)>50:self.move_direction * = -1self.move_counter * = -1平台类(pygame.sprite.Sprite):def __init __(self,x,y,move_x,move_y):pygame.sprite.Sprite .__ init __(自己)img = pygame.image.load('img/platform.png')self.image = pygame.transform.scale(img,(tile_size,tile_size//2))self.rect = self.image.get_rect()self.rect.x = xself.rect.y = yself.move_counter = 0self.move_direction = 1self.move_x = move_xself.move_y = move_ydef update(self):#update敌人(动作)self.rect.x + = self.move_direction * self.move_xself.rect.y + = self.move_direction * self.move_yself.move_counter + = 1如果abs(self.move_counter)>50:self.move_direction * = -1self.move_counter * = -1#液体SPRITE(酸)类Lava(pygame.sprite.Sprite):def __init __(self,x,y):pygame.sprite.Sprite .__ init __(自己)img = pygame.image.load('img/lava2.jpg')self.image = pygame.transform.scale(img,(tile_size,tile_size//2))self.rect = self.image.get_rect()self.rect.x = xself.rect.y = y硬币类(pygame.sprite.Sprite):def __init __(self,x,y):pygame.sprite.Sprite .__ init __(自己)img = pygame.image.load('img/coin.png')self.image = pygame.transform.scale(img,(tile_size//2,tile_size//2))self.rect = self.image.get_rect()self.rect.center =(x,y)类Exit(pygame.sprite.Sprite):def __init __(self,x,y):pygame.sprite.Sprite .__ init __(自己)img = pygame.image.load('img/exit.png')self.image = pygame.transform.scale(img,(tile_size,int(tile_size * 1.5)))self.rect = self.image.get_rect()self.rect.x = xself.rect.y = y玩家=玩家(100,screen_height-130)blob_group = pygame.sprite.Group()platform_group = pygame.sprite.Group()lava_group = pygame.sprite.Group()coin_group = pygame.sprite.Group()exit_group = pygame.sprite.Group()#比分硬币杜比硬币score_coin =硬币(tile_size//2,tile_size//2)coin_group.add(score_coin)#加载关卡数据并创建世界如果path.exists(f'level {level} _data'):pickle_in =打开(f'level {level} _data','rb')world_data = pickle.load(点刺)世界=世界(world_data)#创建按钮restart_button =按钮(screen_width//2-50,screen_height//2 + 100,restart_img)start_button =按钮(screen_width//2-350,screen_height//2,start_img)exit_button =按钮(screen_width//2 + 100,screen_height//2,exit_img)#main循环/正在运行游戏时执行此操作运行=真运行时:clock.tick(fps)#运行fps计时器screen.blit(bg_img,rect)#添加bg imgscreen.blit(earth_img,(100,100))如果main_menu == True:如果exit_button.draw():运行=错误如果start_button.draw():main_menu =假别的:world.draw()#绘制世界瓷砖如果game_over == 0:#活着/不死blob_group.update()platform_group.update()#update分数并检查硬币收集如果pygame.sprite.spritecollide(player,coin_group,True):分数+ = 1coin_fx.play()draw_text("X" + str(score),font_score,白色,tile_size-10、10)blob_group.draw(屏幕)platform_group.draw(屏幕)lava_group.draw(屏幕)coin_group.draw(屏幕)exit_group.draw(屏幕)game_over = player.update(game_over)#如果玩家死了如果game_over == -1:如果restart_button.draw():world_data = []世界= reset_level(等级)game_over = 0分数= 0#如果级别完成重置并进入下一个级别如果game_over == 1:等级+ = 1如果级别< = max_levels:#重置级别world_date = []世界= reset_level(等级)game_over = 0别的:draw_text('WINNER WINNER!',font,blue,(screen_width//2)-140,screen_height//2)#重启游戏如果restart_button.draw():等级= 1#重置级别world_date = []世界= reset_level(等级)game_over = 0分数= 0对于pygame.event.get()中的事件:如果event.type == pygame.QUIT:运行=错误pygame.display.update()#更新显示pygame.quit()#退出游戏 

这是我的外星人精灵

这是我的外星人课程的代码

 类敌人(pygame.sprite.Sprite):def __init __(self,x,y):pygame.sprite.Sprite .__ init __(自己)self.image = pygame.image.load('img/blob.png')self.image = pygame.transform.scale(self.image,(65,35))self.rect = self.image.get_rect()self.rect.x = xself.rect.y = yself.move_direction = 1self.move_counter = 0def update(self):#update敌人(动作)self.rect.x + = self.move_directionself.move_counter + = 1如果abs(self.move_counter)>50:self.move_direction * = -1self.move_counter * = -1 

这是我的播放器类的代码(称为重置")

  def reset(self,x,y):重置按钮下的#Player类,创建播放器类时,出于效率目的而从reset中调用信息(而不是两次键入)self.images_right = []self.images_left = []self.index = 0self.counter = 0对于范围(1,7)中的num:img_right = pygame.image.load(f'img/guy {num} .png')img_right = pygame.transform.scale(img_right,(40,80))img_left = pygame.transform.flip(img_right,True,False)#在x轴{true}而非y轴{false}上翻转右图像self.images_right.append(img_right)self.images_left.append(img_left)self.dead_image = pygame.image.load('img/ghost.png')self.image = self.images_right [self.index]self.rect = self.image.get_rect()self.rect.x = xself.rect.y = yself.width = self.image.get_width()self.height = self.image.get_height()self.vel_y = 0self.jumped = Falseself.direction = 0 

解决方案

使用

 类敌人(pygame.sprite.Sprite):def __init __(self,x,y):pygame.sprite.Sprite .__ init __(自己)self.image_orig = pygame.image.load('img/blob.png')self.image_orig = pygame.transform.scale(self.image_orig,(65,65))self.rect = self.image.get_rect().inflate(-30,-20)self.image = self.image_orig.subsurface(self.rect)self.rect.topleft = x,yself.move_direction = 1self.move_counter = 0 


可以使用 pygame.mask.Mask def hitbox_from_image(surf):image_mask = pygame.mask.from_surface(surf)rect_list = image_mask.get_bounding_rects()返回rect_list [0] .unionall(rect_list)敌人类(pygame.sprite.Sprite):def __init __(self,x,y):pygame.sprite.Sprite .__ init __(自己)self.image_orig = pygame.image.load('img/blob.png')self.image_orig = pygame.transform.scale(self.image_orig,(65,65))self.rect = hitbox_from_image(self.image_orig)self.image = self.image_orig.subsurface(self.rect)self.rect.topleft = x,yself.move_direction = 1self.move_counter = 0


对于 Player 类,我建议您做类似的事情.加载后分别裁剪每个图像(功能 crop_image ).
在绘制精灵之前,在 update 函数中更新 rect 属性:

  def crop_image(surf):rect = hitbox_from_image(surf)返回surf.subsurface(self.rect).copy() 

  class Player():#[...]def更新(自我,游戏结束):#[...]self.rect.x + = dxself.rect.y + = dyself.rec = self.image.get_rect(中心= self.rect.center)screen.blit(self.image,self.rect)def reset(self,x,y):重置按钮下的#Player类,创建播放器类时,出于效率目的而从reset调用信息(而不是键入两次)self.images_right = []self.images_left = []self.index = 0self.counter = 0对于范围(1,7)中的num:img_right = pygame.image.load(f'img/guy {num} .png')img_right = crop_image(pygame.transform.scale(img_right,(40,80)))img_left = pygame.transform.flip(img_right,True,False)#在x轴{true}而非y轴{false}上翻转右图像self.images_right.append(img_right)self.images_left.append(img_left)self.dead_image = crop_image(pygame.image.load('img/ghost.png'))self.image = self.images_right [self.index]self.rect = self.image.get_rect()self.rect.x = xself.rect.y = yself.width = self.image.get_width()self.height = self.image.get_height()self.vel_y = 0self.jumped = Falseself.direction = 0 

Im making a platform game and have a blob (alien) going back and forth on a platform as an obstacle

for the collision I have an issue where my alien sprite hitbox is massive, once my player gets within like .75 of a tile range he instantly dies. I want the hitbox to be much smaller

currently im using pygame.sprite.spritecollide for collision between my player and the blob

Anyway I alter this I can't fix the hitboxes

Is there a way to fix this, I believe pygame.sprite.collide_rect or collide_rect_ratio might work but I don't know how to use the function

Could someone please explain what I should change in my code to fix this (hitboxes)

TLDR; I want to fix my crappy hitboxes, Can you explain how in simple terms

This is the code for the collision

#check for collision with enemies
                if pygame.sprite.spritecollide(self, blob_group, False):
                    game_over = -1
                    game_over_fx.play()

This is my full code

#import modules
import pygame
from pygame.locals import *
from pygame import mixer
import pickle
from os import path


#initiliaze pygamee

pygame.mixer.pre_init(44100,-16,2,512) #volume control

mixer.init()



pygame.init()

#fps
clock = pygame.time.Clock()
font = pygame.font.SysFont('Bauhaus 93', 70)
font_score = pygame.font.SysFont('Bauhaus 93',30)
#screen creation/global variables
screen_width = 800
screen_height = 800
tile_size = 40
fps = 60

game_over = 0
main_menu = True
level = 7
max_levels = 7
score = 0



screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Crashlandingv6')

#color
white = (255,255,255)
red = (255,15,15)
blue = (0,0,200)
#load images
bg_img = pygame.image.load('img/background.jpg')
bg_img = pygame.transform.scale(bg_img, (1000,1000))
earth_img = pygame.image.load('img/earth.png')
earth_img = pygame.transform.scale(earth_img, (100,100))
rect = bg_img.get_rect()
restart_img = pygame.image.load('img/restart_btn.png')
start_img = pygame.image.load('img/start_btn.png')
exit_img = pygame.image.load('img/exit_btn.png')


#Load sounds
pygame.mixer.music.load('img/music.wav')
pygame.mixer.music.play(-1,0.0,15000)
coin_fx = pygame.mixer.Sound('img/coin.wav')
coin_fx.set_volume(0.4)
jump_fx = pygame.mixer.Sound('img/jump.wav')
jump_fx.set_volume(0.4)
game_over_fx = pygame.mixer.Sound('img/gameover.wav')
game_over_fx.set_volume(0.5)
def draw_text(text,font,text_col,x,y):
    img = font.render(text,True, text_col)
    screen.blit(img,(x,y))

#function to reset level
def reset_level(level):
    player.reset(100, screen_height - 130)
    blob_group.empty()
    lava_group.empty()
    exit_group.empty()
    if path.exists(f'level{level}_data'):
        pickle_in = open(f'level{level}_data', 'rb')
        world_data = pickle.load(pickle_in)
    world = World(world_data)
    return world

#create button class

class Button():
    def __init__(self,x,y,image):
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.clicked = False

    def draw(self):
        action = False

        pos = pygame.mouse.get_pos()


        #check for button collision (if button was clicked {action}
        if self.rect.collidepoint(pos):
            if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
                action = True
                self.clicked = True
        if pygame.mouse.get_pressed()[0] == 0:
            self.clicked = False
        #draw button to screen
        screen.blit(self.image,self.rect)

        return action

#class for player
class Player():
    def __init__(self, x, y):
        self.reset(x,y)

    def update(self,game_over):
        dx = 0 #delta x
        dy = 0 #delta y
        walk_cooldown = 4 #speed
        col_thresh = 20

        if game_over == 0: #if game is running gameover = 0 if game is over gameover = -1
            #get keypresses (controls)
            key = pygame.key.get_pressed()
            if key[pygame.K_SPACE] and self.jumped == False:
                jump_fx.play()
                self.vel_y = -15
                self.jumped = True

            if key[pygame.K_LEFT]:
                dx -= 5
                self.counter += 1
                self.direction = -1
            if key[pygame.K_RIGHT]:
                dx += 5
                self.counter += 1
                self.direction = 1
            if key[pygame.K_LEFT] == False and key[pygame.K_RIGHT] == False:
                self.counter = 0
                self.index = 0
                if self.direction == 1:
                    self.image = self.images_right[self.index]
                if self.direction == -1:
                    self.image = self.images_left[self.index]

            #TO DO < insert here !!
            # add idle player animation if all buttons are false set player to idle



            # players animation
            if self.counter > walk_cooldown:
                self.counter = 0
                self.index += 1
                if self.index >= len(self.images_right):
                    self.index = 0
                if self.direction == 1:
                    self.image = self.images_right[self.index]
                if self.direction == -1:
                    self.image = self.images_left[self.index]



            #add gravity
            self.vel_y += 1
            if self.vel_y > 10:
                self.vel_y = 10
            dy += self.vel_y

            #check for collision

            for tile in world.tile_list:
                #x direction collision
                if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
                    dx=0




                #y direction collision
                if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
                    #check if below ground (jumping)
                    if self.vel_y <0:
                        dy = tile[1].bottom - self.rect.top
                        self.vel_y = 0
                    #check if above ground(falling)
                    elif self.vel_y >= 0:
                        dy = tile[1].top - self.rect.bottom
                        self.jumped = False
                #check for collision with enemies
                if pygame.sprite.spritecollide(self, blob_group, False):
                    game_over = -1
                    game_over_fx.play()



                #check for collision with lava
                if pygame.sprite.spritecollide(self,lava_group,False):
                    game_over = -1


                # check for collision with exit
                if pygame.sprite.spritecollide(self, exit_group, False):
                    game_over = 1

                #platform collision
                for platform in platform_group:
                    #check for x collision
                    if platform.rect.colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
                        dx = 0
                    # y collision
                    if platform.rect.colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
                        #check if below platform
                        if abs((self.rect.top + dy) - platform.rect.bottom) < col_thresh:
                            self.vel_y = 0
                            dy = platform.rect.bottom - self.rect.top
                        #check if above platform
                        elif abs((self.rect.bottom + dy) - platform.rect.top) < col_thresh:
                            self.rect.bottom = platform.rect.top - 1
                            self.in_air = False
                            dy = 0
                        #Move sideways w platform
                        if platform.move_x != 0:
                            self.rect.x += platform.move_direction





            #if gameover (recall gameover = -1 gamerunning = 0)
        elif game_over == -1:
            self.image = self.dead_image
            draw_text('GAME OVER!', font, red, (screen_width //2) - 200, screen_height //2)
            if self.rect.y > 200:
                self.rect.y -= 5
        #update player coordinates
        self.rect.x += dx
        self.rect.y += dy



        #draw player onto screen
        screen.blit(self.image, self.rect)
        #for rect outlines uncomment #pygame.draw.rect(screen,(255,255,255), self.rect, 2)

        return game_over

    def reset(self,x,y): #Player class under reset button , when player  class is created info gets called from reset for efficiency purposes (instead of typing out twice)
        self.images_right = []
        self.images_left = []
        self.index = 0
        self.counter = 0
        for num in range(1, 7):
            img_right = pygame.image.load(f'img/guy{num}.png')
            img_right = pygame.transform.scale(img_right, (40, 80))
            img_left = pygame.transform.flip(img_right, True, False)  # flips right image on the x axis {true} and not y axis {false}
            self.images_right.append(img_right)
            self.images_left.append(img_left)
        self.dead_image = pygame.image.load('img/ghost.png')
        self.image = self.images_right[self.index]
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.width = self.image.get_width()
        self.height = self.image.get_height()
        self.vel_y = 0
        self.jumped = False
        self.direction = 0

#class for tiles
class World():
    def __init__(self,data):
        self.tile_list = []

        #load images
        dirt_img = pygame.image.load('img/dirt.png')
        moonrock_img = pygame.image.load('img/moonrock.png')



#game map
        row_count = 0
        for row in data:
            col_count = 0
            for tile in row:
                if tile == 1: #replace with dirt
                    img = pygame.transform.scale(dirt_img,(tile_size,tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img,img_rect)
                    self.tile_list.append(tile)
                if tile == 2: #replace with moonrock
                    img = pygame.transform.scale(moonrock_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 3: #replace with alien
                    blob = Enemy(col_count * tile_size, row_count * tile_size + 10)
                    blob_group.add(blob)
                if tile == 4:
                    platform = Platform(col_count * tile_size, row_count * tile_size,1,0) # y direction
                    platform_group.add(platform)
                if tile == 5:
                    platform = Platform(col_count * tile_size, row_count * tile_size,0,1)
                    platform_group.add(platform)
                if tile == 6: #replace with acid
                    lava = Lava(col_count * tile_size, row_count * tile_size+(tile_size //2))
                    lava_group.add(lava)
                if tile == 7:
                    coin = Coin(col_count * tile_size + (tile_size //2), row_count * tile_size + (tile_size // 2))
                    coin_group.add(coin)
                if tile == 8:
                    exit = Exit(col_count * tile_size, row_count * tile_size - (tile_size//2))
                    exit_group.add(exit)
                col_count += 1
            row_count += 1


    def draw(self): #draws tiles to screen
        for tile in self.tile_list:
            screen.blit(tile[0],tile[1])
    #for rectangle outlines uncomment       #pygame.draw.rect(screen,(255,255,255), tile[1], 1)



#ENEMY SPRITE class
class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load('img/blob.png')
        self.image = pygame.transform.scale(self.image, (65,35))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.move_direction = 1
        self.move_counter = 0

    def update(self): #update enemy (movement)
        self.rect.x += self.move_direction
        self.move_counter += 1
        if abs(self.move_counter) > 50:
            self.move_direction *= -1
            self.move_counter *= -1

class Platform(pygame.sprite.Sprite):
    def __init__(self, x, y, move_x, move_y):
        pygame.sprite.Sprite.__init__(self)
        img = pygame.image.load('img/platform.png')
        self.image = pygame.transform.scale(img, (tile_size, tile_size // 2))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.move_counter = 0
        self.move_direction = 1
        self.move_x = move_x
        self.move_y = move_y

    def update(self): #update enemy (movement)
        self.rect.x += self.move_direction * self.move_x
        self.rect.y += self.move_direction * self.move_y
        self.move_counter += 1
        if abs(self.move_counter) > 50:
            self.move_direction *= -1
            self.move_counter *= -1

#LIQUID SPRITE (acid)
class Lava(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        img = pygame.image.load('img/lava2.jpg')
        self.image = pygame.transform.scale(img, (tile_size, tile_size//2))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

class Coin(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        img = pygame.image.load('img/coin.png')
        self.image = pygame.transform.scale(img, (tile_size//2, tile_size//2))
        self.rect = self.image.get_rect()
        self.rect.center = (x,y)




class Exit(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        img = pygame.image.load('img/exit.png')
        self.image = pygame.transform.scale(img, (tile_size, int(tile_size * 1.5)))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y






player = Player(100,screen_height - 130)
blob_group = pygame.sprite.Group()
platform_group = pygame.sprite.Group()
lava_group = pygame.sprite.Group()
coin_group = pygame.sprite.Group()
exit_group = pygame.sprite.Group()


#score coin dumby coin
score_coin = Coin(tile_size//2, tile_size//2)
coin_group.add(score_coin)
#load in level data and create world

if path.exists(f'level{level}_data'):
    pickle_in = open(f'level{level}_data', 'rb')
    world_data = pickle.load(pickle_in)
world = World(world_data)

#create buttons
restart_button = Button(screen_width // 2 - 50, screen_height // 2 + 100, restart_img)
start_button = Button(screen_width// 2 - 350, screen_height // 2, start_img)
exit_button = Button(screen_width// 2 + 100, screen_height // 2, exit_img)
#main loop/ WHILE GAME IS RUNNING DO THIS
run = True
while run:
    clock.tick(fps) #run the fps timers
    screen.blit(bg_img,rect) #add bg img
    screen.blit(earth_img,(100,100))


    if main_menu == True:
        if exit_button.draw():
            run = False
        if start_button.draw():
            main_menu = False
    else:

        world.draw() #draw the world tiles
        if game_over == 0: # while alive / not dead
            blob_group.update()
            platform_group.update()

            #update score and  checking for coin collection

            if pygame.sprite.spritecollide(player,coin_group,True):
                score += 1
                coin_fx.play()

            draw_text("X " + str(score), font_score ,white, tile_size - 10, 10)
        blob_group.draw(screen)
        platform_group.draw(screen)
        lava_group.draw(screen)
        coin_group.draw(screen)
        exit_group.draw(screen)


        game_over = player.update(game_over)


        #if player is dead
        if game_over == -1:
            if restart_button.draw():
                world_data = []
                world = reset_level(level)
                game_over = 0
                score = 0

        #If level complete reset and next level
        if game_over == 1:
            level += 1
            if level <= max_levels:
                #reset level
                world_date = []
                world = reset_level(level)
                game_over = 0
            else:
                draw_text('WINNER WINNER!', font, blue, (screen_width //2) - 140, screen_height // 2)
                #restart game
                if restart_button.draw():
                    level = 1
                    # reset level
                    world_date = []
                    world = reset_level(level)
                    game_over = 0
                    score = 0

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False


    pygame.display.update() #update display

pygame.quit() #quit game

This is my alien sprite

This is the code for my Alien Class

class Enemy(pygame.sprite.Sprite):
        def __init__(self, x, y):
            pygame.sprite.Sprite.__init__(self)
            self.image = pygame.image.load('img/blob.png')
            self.image = pygame.transform.scale(self.image, (65,35))
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.y = y
            self.move_direction = 1
            self.move_counter = 0
    
        def update(self): #update enemy (movement)
            self.rect.x += self.move_direction
            self.move_counter += 1
            if abs(self.move_counter) > 50:
                self.move_direction *= -1
                self.move_counter *= -1

This is the code for my player class (Ik its called reset)

def reset(self,x,y): #Player class under reset button , when player  class is created info gets called from reset for efficiency purposes (instead of typing out twice)
        self.images_right = []
        self.images_left = []
        self.index = 0
        self.counter = 0
        for num in range(1, 7):
            img_right = pygame.image.load(f'img/guy{num}.png')
            img_right = pygame.transform.scale(img_right, (40, 80))
            img_left = pygame.transform.flip(img_right, True, False)  # flips right image on the x axis {true} and not y axis {false}
            self.images_right.append(img_right)
            self.images_left.append(img_left)
        self.dead_image = pygame.image.load('img/ghost.png')
        self.image = self.images_right[self.index]
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.width = self.image.get_width()
        self.height = self.image.get_height()
        self.vel_y = 0
        self.jumped = False
        self.direction = 0

解决方案

Use inflate to shrink the rectangle size.
However, since the rect attribute is used for collision detection and drawing the sprite, you will need to create a smaller image. Use pygame.Surface.subsurface to create a new surface that references a parent of the original surface:

class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        
        self.image_orig = pygame.image.load('img/blob.png')
        self.image_orig = pygame.transform.scale(self.image_orig, (65, 65))        
        
        self.rect = self.image.get_rect().inflate(-30, -20)     
        self.image = self.image_orig.subsurface(self.rect)
        self.rect.topleft = x, y
        
        self.move_direction = 1
        self.move_counter = 0


The size of the hitbox can be automatically detected using pygame.mask.Mask and pygame.mask.from_surface :

def hitbox_from_image(surf):
    image_mask = pygame.mask.from_surface(surf)
    rect_list = image_mask.get_bounding_rects()
    return rect_list[0].unionall(rect_list) 

class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)

        self.image_orig = pygame.image.load('img/blob.png')
        self.image_orig = pygame.transform.scale(self.image_orig, (65, 65))        
        
        self.rect = hitbox_from_image(self.image_orig)     
        self.image = self.image_orig.subsurface(self.rect)
        self.rect.topleft = x, y

        self.move_direction = 1
        self.move_counter = 0


For the Player class I recommend you to do something similar. Crop each image separately after loading (funtion crop_image).
Update the rect attribute in the update function, before drawing the sprite:

def crop_image(surf):
    rect = hitbox_from_image(surf)
    return surf.subsurface(self.rect).copy()

class Player():
    # [...]

    def update(self,game_over):
        # [...]

        self.rect.x += dx
        self.rect.y += dy
        self.rec = self.image.get_rect(center = self.rect.center)

        screen.blit(self.image, self.rect)

    def reset(self,x,y): #Player class under reset button , when player  class is created info gets called from reset for efficiency purposes (instead of typing out twice)
        self.images_right = []
        self.images_left = []
        self.index = 0
        self.counter = 0
        for num in range(1, 7):
            img_right = pygame.image.load(f'img/guy{num}.png')
            img_right = crop_image(pygame.transform.scale(img_right, (40, 80)))
            img_left = pygame.transform.flip(img_right, True, False)  # flips right image on the x axis {true} and not y axis {false}
            self.images_right.append(img_right)
            self.images_left.append(img_left)
        self.dead_image = crop_image(pygame.image.load('img/ghost.png'))
        self.image = self.images_right[self.index]
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.width = self.image.get_width()
        self.height = self.image.get_height()
        self.vel_y = 0
        self.jumped = False
        self.direction = 0

这篇关于PYGAME Sprite rect碰撞vs sprite碰撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆