使用Sprite和基于图块的地图进行2D Pygame滚动

如何解决使用Sprite和基于图块的地图进行2D Pygame滚动

我目前正在尝试使用滚动相机在python中制作2d平台游戏。最初,我只使用rect样式的对象制作游戏,但是与仅使用sprite相比,这使碰撞非常困难。

所以现在我要使用精灵为敌人和主要玩家重写游戏,但是我不知道为什么滚动功能将不再起作用。似乎似乎是一个扩展问题,但我不知道。

当我关闭滚动时,游戏运行正常。

谢谢你们,如果您看到任何跳出来的信息,请告诉我。 抱歉,代码有点混乱,我仍然习惯于整个pygame布局。

import pygame,sys

clock = pygame.time.Clock()

from pygame.locals import *
pygame.init() # initiates pygame

pygame.display.set_caption('Pygame Platformer')

WINDOW_SIZE = (1200,800)

screen = pygame.display.set_mode(WINDOW_SIZE,32) # initiate the window

display = pygame.Surface((150,100)) # used as the surface for rendering,which is scaled

moving_right = False
moving_left = False
vertical_momentum = 0
air_timer = 0
scroll = [0,0]
class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((8,8))
        self.image.fill((255,0))
        self.rect = self.image.get_rect()
        self.rect.centerx = 100
        self.rect.bottom = 50
        self.isJump = False
        self.jumpCount = 5
    def update(self):
        self.speedx = 0
        self.rect.x += self.speedx

class Mob(pygame.sprite.Sprite):
    def __init__(self,x,y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10,10))
        self.image.fill((255,255,0))
        self.rect = self.image.get_rect()
        self.rect.centerx = y
        self.rect.bottom = x
        self.speedx = 0
        self.speedy = 0

    def update(self):
        self.speedx = 0
        self.speedy = 0
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT]:
            self.speedx = -10
        if keystate[pygame.K_RIGHT]:
            self.speedx = 10
        if keystate[pygame.K_SPACE]:
            self.speedy = -30
        self.rect.x += 0
        self.rect.y += 0
#def load_map(path):
 #   f = open(path + '.txt','r')
  #  data = f.read()
   # f.close()
    #data = data.split('\n')
   # game_map = []
   # for row in data:
    #    game_map.append(list(row))
   # return game_map

#ame_map = load_map('data/pictures/map')
game_map = [['0','0','0'],['0','2',['2','2'],['1','1','1'],'1']]

grass_img = pygame.image.load('data/pictures/Purple_grass.png')
dirt_img = pygame.image.load('data/pictures/purple_tile.png')

player = Player()

def collision_test(rect,tiles):
    hit_list = []
    for tile in tiles:
        if rect.colliderect(tile):
            hit_list.append(tile)
    return hit_list

def move(rect,movement,tiles):
    collision_types = {'top':False,'bottom':False,'right':False,'left':False}
    rect.x += movement[0]
    hit_list = collision_test(rect,tiles)
    for tile in hit_list:
        if movement[0] > 0:
            rect.right = tile.left
            collision_types['right'] = True
        elif movement[0] < 0:
            rect.left = tile.right
            collision_types['left'] = True
    rect.y += movement[1]
    hit_list = collision_test(rect,tiles)
    for tile in hit_list:
        if movement[1] > 0:
            rect.bottom = tile.top
            collision_types['bottom'] = True
        elif movement[1] < 0:
            rect.top = tile.bottom
            collision_types['top'] = True
    return rect,collision_types




all_sprites = pygame.sprite.Group()
mobs = []
mob1 = Mob(10,10)
mobs.append(mob1)
all_sprites.add(player,mobs)
while True: # game loop
    display.fill((146,244,255)) # clear screen by filling it with blue
    #scroll
    scroll[0] += (player.rect.x - scroll[0] -100 ) / 10
    scroll[1] += (player.rect.y - scroll[1] -52) / 10
    all_sprites.update()

    tile_rects = []
    y = 0
    for layer in game_map:
        x = 0
        for tile in layer:
            if tile == '1':
                display.blit(dirt_img,(x * 8 - int(scroll[0]),y * 8 - int(scroll[1])))
            if tile == '2':
                display.blit(grass_img,y * 8 - int(scroll[1])))
            if tile != '0':
                tile_rects.append(pygame.Rect(x * 8,y * 8,8,8))
            x += 1
        y += 1

    player_movement = [0,0]
    if moving_right == True:
        player_movement[0] += 1
    if moving_left == True:
        player_movement[0] -= 1
    player_movement[1] += vertical_momentum
    vertical_momentum += 0.3
    if vertical_momentum > 3:
        vertical_momentum = 3

    player.rect,collisions = move(player.rect,player_movement,tile_rects)

    if collisions['bottom'] == True:
        air_timer = 0
        player.jumpCount = 0
    else:
        air_timer += 1


    for mob in mobs:
        if pygame.sprite.collide_rect(player,mob):
            #mob.image.fill((255,255))
            mobs.pop(mobs.index(mob))
            print("collide")
            all_sprites.remove(mob)

        else:
            mob.image.fill((255,0))

    all_sprites.draw(display)


    for event in pygame.event.get(): # event loop
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYDOWN:
            if event.key == K_RIGHT:
                moving_right = True
            if event.key == K_LEFT:
                moving_left = True
            if event.key == K_SPACE:
                if air_timer < 6:
                    vertical_momentum = -5
        if event.type == KEYUP:
            if event.key == K_RIGHT:
                moving_right = False
            if event.key == K_LEFT:
                moving_left = False
        
    screen.blit(pygame.transform.scale(display,WINDOW_SIZE),(0,0))
    pygame.display.update()
    clock.tick(60)

解决方法

首先:在所有移动和碰撞之后,您应该计算scroll

第二:您必须从所有对象中减去scroll-甚至是玩家和暴民

for item in all_sprites:
    display.blit(item.image,(item.rect.x - scroll[0],item.rect.y - scroll[1]))

最少的工作代码。

scroll可以工作,但是它并不流畅,所以我更喜欢简单的版本

scroll[0] = int(player.rect.centerx - 75) # surface_width//2
scroll[1] = int(player.rect.centery - 50) # surface_height//2

两者都在代码中但在注释中

import pygame,sys
from pygame.locals import *

# --- constants ---

WINDOW_SIZE = (1200,800)

# --- classes ---

class Player(pygame.sprite.Sprite):
    
    def __init__(self):
        #pygame.sprite.Sprite.__init__(self)
        super().__init__()
        
        self.image = pygame.Surface((8,8))
        self.image.fill((255,0))
        
        self.rect = self.image.get_rect()
        self.rect.centerx = 100
        self.rect.bottom = 50
        
        self.isJump = False
        self.jumpCount = 5
        
    def update(self):
        self.speedx = 0
        self.rect.x += self.speedx

class Mob(pygame.sprite.Sprite):
    
    def __init__(self,x,y):
        #pygame.sprite.Sprite.__init__(self)
        super().__init__()
        
        self.image = pygame.Surface((10,10))
        self.image.fill((255,255,0))
        
        self.rect = self.image.get_rect()
        self.rect.centerx = y
        self.rect.bottom = x
        
        self.speedx = 0
        self.speedy = 0

    def update(self):
        self.speedx = 0
        self.speedy = 0
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT]:
            self.speedx = -10
        if keystate[pygame.K_RIGHT]:
            self.speedx = 10
        if keystate[pygame.K_SPACE]:
            self.speedy = -30
        self.rect.x += 0
        self.rect.y += 0

# --- functions ---

#def load_map(path):
 #   f = open(path + '.txt','r')
  #  data = f.read()
   # f.close()
    #data = data.split('\n')
   # game_map = []
   # for row in data:
    #    game_map.append(list(row))
   # return game_map

def collision_test(rect,tiles):
    hit_list = []

    for tile in tiles:
        if rect.colliderect(tile):
            hit_list.append(tile)
            
    return hit_list

def move(rect,movement,tiles):
    collision_types = {'top':False,'bottom':False,'right':False,'left':False}
    
    rect.x += movement[0]
    hit_list = collision_test(rect,tiles)
    
    for tile in hit_list:
        if movement[0] > 0:
            rect.right = tile.left
            collision_types['right'] = True
        elif movement[0] < 0:
            rect.left = tile.right
            collision_types['left'] = True
            
    rect.y += movement[1]
    hit_list = collision_test(rect,tiles)
    
    for tile in hit_list:
        if movement[1] > 0:
            rect.bottom = tile.top
            collision_types['bottom'] = True
        elif movement[1] < 0:
            rect.top = tile.bottom
            collision_types['top'] = True
            
    return rect,collision_types

# --- main ---

# you could put in class Map
#ame_map = load_map('data/pictures/map')
game_map = [['0','0','0'],['0','2',['2','2'],['1','1','1'],'1']]


# - init -

pygame.init() 

pygame.display.set_caption('Pygame Platformer')

screen = pygame.display.set_mode(WINDOW_SIZE,32) # initiate the window

display = pygame.Surface((150,100)) # used as the surface for rendering,which is scaled

moving_right = False   # you could put in class Player
moving_left = False    # you could put in class Player
vertical_momentum = 0  # you could put in class Player
air_timer = 0          # you could put in class Player
scroll = [0,0]        # you could put in class Player

#grass_img = pygame.image.load('data/pictures/Purple_grass.png')
#dirt_img = pygame.image.load('data/pictures/purple_tile.png')

grass_img = pygame.surface.Surface((8,8))  # you could put in class Map
grass_img.fill((0,0))                # you could put in class Map
                    
dirt_img = pygame.surface.Surface((8,8))  # you could put in class Map
dirt_img.fill((255,64,64))              # you could put in class Map

player = Player()
mobs = [Mob(10,10)]

all_sprites = pygame.sprite.Group()
all_sprites.add(player,mobs)

# - you can get it once - # you could put in class Map

tile_rects = []
for y,layer in enumerate(game_map):
    for x,tile in enumerate(layer):
        if tile != '0':
            tile_rects.append(pygame.Rect(x * 8,y * 8,8,8))

# - loop -

clock = pygame.time.Clock()

while True:

    # - all updates -
    
    all_sprites.update()

    player_movement = [0,0]
    if moving_right == True:
        player_movement[0] += 1
    if moving_left == True:
        player_movement[0] -= 1
    player_movement[1] += vertical_momentum
    vertical_momentum += 0.3
    if vertical_momentum > 3:
        vertical_momentum = 3

    player.rect,collisions = move(player.rect,player_movement,tile_rects)

    if collisions['bottom'] == True:
        air_timer = 0
        player.jumpCount = 0
    else:
        air_timer += 1

    for mob in mobs:
        if pygame.sprite.collide_rect(player,mob):
            #mob.image.fill((255,255))
            mobs.pop(mobs.index(mob))
            print("collide")
            all_sprites.remove(mob)

        else:
            mob.image.fill((255,0))

    # - all draws -
    
    # scroll calculate after all moves 
    scroll[0] = int(player.rect.centerx - 75) # surface_width//2
    scroll[1] = int(player.rect.centery - 50) # surface_height//2

    #scroll[0] += (player.rect.x - scroll[0] -100 ) / 10
    #scroll[1] += (player.rect.y - scroll[1] -52) / 10
    
    display.fill((146,244,255)) # clear screen by filling it with blue

    for y,layer in enumerate(game_map):
        for x,tile in enumerate(layer):
            if tile == '1':
                display.blit(dirt_img,(x * 8 - scroll[0],y * 8 - scroll[1]))
            if tile == '2':
                display.blit(grass_img,y * 8 - scroll[1]))

    for item in all_sprites:
        display.blit(item.image,item.rect.y - scroll[1]))
    #all_sprites.draw(display)

    screen.blit(pygame.transform.scale(display,WINDOW_SIZE),(0,0))
    pygame.display.update()
    clock.tick(60)

    # - all events -
    
    for event in pygame.event.get(): # event loop
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYDOWN:
            if event.key == K_RIGHT:
                moving_right = True
            if event.key == K_LEFT:
                moving_left = True
            if event.key == K_SPACE:
                if air_timer < 6:
                    vertical_momentum = -5
        if event.type == KEYUP:
            if event.key == K_RIGHT:
                moving_right = False
            if event.key == K_LEFT:
                moving_left = False
        

编辑:

具有更多类和其他更改的版本(例如pygame.math.Vector2()

# PE8: all imports at the beginning
import pygame,sys
#from pygame.locals import * # PEP8: `import *` is not preferred

# --- constants ---

WINDOW_SIZE = (1200,800)

# --- classes --- # PEP8: all classes before main part

class Player(pygame.sprite.Sprite):
                        # PEP8: empty line before method
    def __init__(self):
        #pygame.sprite.Sprite.__init__(self)  # Python 2 & 3
        super().__init__() # only Python 3
        
        self.image = pygame.Surface((8,255))

        self.rect = self.image.get_rect()
        self.rect.centerx = 100
        self.rect.bottom = 50
        
        self.is_jump = False   # PEP8: `lower_case_names` for variables
        self.jump_count = 5    # PEP8: `lower_case_names` for variables
        
        self.movement = pygame.math.Vector2(0,0)
        self.speed = pygame.math.Vector2(0,0)

        self.moving_right = False
        self.moving_left = False
        self.vertical_momentum = 0
        self.air_timer = 0

    def update(self):
        self.speed.x = 0
        #self.rect.x += self.speed.x

    def draw(self,screen,offset):
        screen.blit(self.image,self.rect.move(-offset))
        
class Mob(pygame.sprite.Sprite):
    
    def __init__(self,y):
        #pygame.sprite.Sprite.__init__(self)  # Python 2 & 3
        super().__init__() # only Python 3

        self.image = pygame.Surface((10,0))
        self.rect = self.image.get_rect()
        self.rect.centerx = y
        self.rect.bottom = x
        self.speedx = 0
        self.speedy = 0

    def update(self):
        self.speedx = 0
        self.speedy = 0
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT]:
            self.speedx = -10
        if keystate[pygame.K_RIGHT]:
            self.speedx = 10
        if keystate[pygame.K_SPACE]:
            self.speedy = -30
        self.rect.x += 0
        self.rect.y += 0
        
    def draw(self,self.rect.move(-offset))
        
#def load_map(path):
 #   f = open(path + '.txt','r')
  #  data = f.read()
   # f.close()
    #data = data.split('\n')
   # game_map = []
   # for row in data:
    #    game_map.append(list(row))
   # return game_map

class Map():
    
    def __init__(self,game_map):
        self.game_map = game_map
        
        #self.grass_img = pygame.image.load('data/pictures/Purple_grass.png')
        #self.dirt_img = pygame.image.load('data/pictures/purple_tile.png')

        self.grass_img = pygame.surface.Surface((8,8))
        self.grass_img.fill((0,0))
                            
        self.dirt_img = pygame.surface.Surface((8,8))
        self.dirt_img.fill((255,64))

        # - you can calculate it only once -

        self.tile_rects = []

        for y,layer in enumerate(self.game_map):
            for x,tile in enumerate(layer):
                if tile != '0':
                    self.tile_rects.append(pygame.Rect(x*8,y*8,8))

    def draw(self,offset):
        
        for y,tile in enumerate(layer):
                if tile == '1':
                    display.blit(self.dirt_img,(x*8 - offset.x,y*8 - offset.y))
                elif tile == '2':
                    display.blit(self.grass_img,y*8 - offset.y))
        
# --- functions --- # PEP8: all functions before main part

def collision_test(rect,tiles):
    hit_list = []
    
    for tile in tiles:
        if rect.colliderect(tile):
            hit_list.append(tile)
            
    return hit_list

def move(player,map_game):
    
    collision_types = {'top': False,'bottom': False,'right': False,'left': False} # PEP8: spaces
    
    player.rect.x += player.movement.x
    
    hit_list = collision_test(player.rect,map_game.tile_rects)
    
    for tile in hit_list:
        if player.movement.x > 0:
            player.rect.right = tile.left
            collision_types['right'] = True
            break
        elif player.movement.x < 0:
            player.rect.left = tile.right
            collision_types['left'] = True
            break
            
    player.rect.y += player.movement.y
    
    hit_list = collision_test(player.rect,map_game.tile_rects)
    
    for tile in hit_list:
        if player.movement.y > 0:
            player.rect.bottom = tile.top
            collision_types['bottom'] = True
            break
        elif player.movement.y < 0:
            player.rect.top = tile.bottom
            collision_types['top'] = True
            break
            
    return collision_types

# --- main ---

#ame_map = load_map('data/pictures/map')
game_map = [['0','1']]


# - init -

pygame.init()
pygame.display.set_caption('Pygame Platformer')

screen = pygame.display.set_mode(WINDOW_SIZE,which is scaled

scroll = pygame.math.Vector2(0,0)

map_data = Map(game_map)
player = Player()
mobs = [Mob(10,10),Mob(50,50)]

all_sprites = pygame.sprite.Group()
all_sprites.add(player,mobs)

# - main loop -

clock = pygame.time.Clock()

while True:

    # - all updates -
    #all_sprites.update()

    player.movement.update(0,0)
    
    if player.moving_right == True:
        player.movement.x += 1
            
    if player.moving_left == True:
        player.movement.x -= 1
        
    player.movement.y += player.vertical_momentum
    
    player.vertical_momentum += 0.3
    if player.vertical_momentum > 3:
        player.vertical_momentum = 3

    collisions = move(player,map_data)

    if collisions['bottom'] == True:
        player.air_timer = 0
        player.jump_count = 0
        player.vertical_momentum = 0
    else:
        player.air_timer += 1

        
    for mob in mobs:
        if pygame.sprite.collide_rect(player,255))
            mobs.pop(mobs.index(mob))
            print("collide")
            all_sprites.remove(mob)
        else:
            mob.image.fill((255,0))

    # - all draws -

    # scroll
    scroll.update(player.rect.centerx - 75,player.rect.centery - 50)

    offset = pygame.math.Vector2(int(scroll.x),int(scroll.y))

    display.fill((146,255))  # PEP8: spaces after `,`

    map_data.draw(display,offset)
    
    for item in all_sprites:
        item.draw(display,offset)

    screen.blit(pygame.transform.scale(display,0))
    pygame.display.update()

    clock.tick(60)
    
    # - all events -

    for event in pygame.event.get(): # event loop
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
            
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
                
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                player.moving_right = True
            if event.key == pygame.K_LEFT:
                player.moving_left = True
            if event.key == pygame.K_SPACE:
                if player.air_timer < 6:
                    player.vertical_momentum = -5
                    
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                player.moving_right = False
            if event.key == pygame.K_LEFT:
                player.moving_left = False
                

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-