PYGAME Sprite rect碰撞vs sprite碰撞 [英] PYGAME Sprite rect collision vs sprite collision
问题描述
我正在做一个平台游戏,并在平台上来回传播一个斑点(异形)作为障碍物
对于碰撞,我遇到了一个问题,即我的外星精灵击打盒很大,一旦我的玩家进入瓷砖范围的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
可以使用 对于 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 This is my full code This is my alien sprite This is the code for my Alien Class This is the code for my player class (Ik its called reset)
Use
The size of the hitbox can be automatically detected using
For the
这篇关于PYGAME Sprite rect碰撞vs sprite碰撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! 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
#check for collision with enemies
if pygame.sprite.spritecollide(self, blob_group, False):
game_over = -1
game_over_fx.play()
#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
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
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
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
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
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