You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
12 KiB

9 months ago
from ..components import info
import pygame
from .. import tools, setup
from .. import constants as C
9 months ago
from .. components import player,stuff,brick,box,enemy
9 months ago
import os
import json
9 months ago
class Level:
9 months ago
def start(self,game_info):
self.game_info = game_info
9 months ago
self.finished = False
9 months ago
self.next = 'game_over'
self.info = info.Info('level',self.game_info)
9 months ago
self.load_map_data()
9 months ago
self.setup_background()
9 months ago
self.setup_start_positions()
9 months ago
self.setup_player()
9 months ago
self.setup_ground_items()
9 months ago
self.setup_bricks_and_boxes()
self.setup_enemies()
9 months ago
self.setup_checkpoints()
9 months ago
9 months ago
def load_map_data(self):
file_name = 'level_1.json'
file_path = os.path.join('source/data/maps',file_name)
with open(file_path) as f:
self.map_data = json.load(f)
9 months ago
def setup_background(self):
9 months ago
self.image_name = self.map_data['image_name']
self.background = setup.GRAPHICS[self.image_name]
9 months ago
rect = self.background.get_rect()
self.background = pygame.transform.scale(self.background,(int(rect.width * C.BG_MULTI),
int(rect.height * C.BG_MULTI)))
self.background_rect = self.background.get_rect()
9 months ago
self.game_window = setup.SCREEN.get_rect()
self.game_ground = pygame.Surface((self.background_rect.width,self.background_rect.height))
def setup_start_positions(self):
self.positions = []
for data in self.map_data['maps']:
self.positions.append((data['start_x'],data['end_x'],data['player_x'],data['player_y']))
self.start_x,self.end_x,self.player_x,self.player_y = self.positions[0]
9 months ago
def setup_player(self):
self.player = player.Player('mario')
9 months ago
self.player.rect.x = self.game_window.x + self.player_x
self.player.rect.bottom = self.player_y
9 months ago
9 months ago
def setup_ground_items(self):
self.ground_items_group = pygame.sprite.Group() # 组存放多个精灵类,方便处理
for name in ['ground','pipe','step']:
for item in self.map_data[name]:
self.ground_items_group.add(stuff.Item(item['x'],item['y'],item['width'],item['height'],name))
9 months ago
9 months ago
def setup_bricks_and_boxes(self):
9 months ago
self.brick_group = pygame.sprite.Group()
9 months ago
self.box_group = pygame.sprite.Group()
9 months ago
self.coin_group = pygame.sprite.Group()
self.powerup_group = pygame.sprite.Group()
9 months ago
if'brick' in self.map_data:
for brick_data in self.map_data['brick']: # 遍历得到xy坐标以及type
x,y = brick_data['x'],brick_data['y']
brick_type = brick_data['type']
9 months ago
if brick_type == 0:
if 'brick_num' in brick_data:
#TODO Batch bricks
pass
else:
self.brick_group.add(brick.Brick(x, y, brick_type,None))
elif brick_type == 1:
self.brick_group.add(brick.Brick(x, y, brick_type, self.coin_group))
9 months ago
else:
9 months ago
self.brick_group.add(brick.Brick(x, y, brick_type, self.powerup_group))
9 months ago
9 months ago
if 'box' in self.map_data:
for box_data in self.map_data['box']: # 遍历得到xy坐标以及type
x, y = box_data['x'], box_data['y']
box_type = box_data['type']
9 months ago
if box_type == 1:
self.box_group.add(box.Box(x, y, box_type, self.coin_group))
else:
self.box_group.add(box.Box(x, y, box_type,self.powerup_group))
9 months ago
def setup_enemies(self):
9 months ago
self.dying_group = pygame.sprite.Group()
self.shell_group = pygame.sprite.Group()
self.enemy_group = pygame.sprite.Group() # 初始化
9 months ago
self.enemy_group_dict = {}
for enemy_group_data in self.map_data['enemy']: # 字典存放
group = pygame.sprite.Group()
for enemy_group_id,enemy_list in enemy_group_data.items():
for enemy_data in enemy_list:
group.add(enemy.create_enemy(enemy_data)) # 调用 ce
self.enemy_group_dict[enemy_group_id] = group
9 months ago
def setup_checkpoints(self):
self.checkpoint_group = pygame.sprite.Group()
for item in self.map_data['checkpoint']:
x,y,w,h = item['x'],item['y'],item['width'],item['height']
checkpoint_type = item['type']
enemy_groupid = item.get('enemy_groupid')
self.checkpoint_group.add(stuff.Checkpoint(x,y,w,h,checkpoint_type,enemy_groupid))
9 months ago
9 months ago
9 months ago
def update(self, surface, keys):
9 months ago
self.current_time = pygame.time.get_ticks()
9 months ago
self.player.update(keys)
9 months ago
if self.player.dead:
if self.current_time - self.player.death_timer > 3000:
self.finished = True
self.update_game_info()
else:
self.update_player_position()
9 months ago
self.check_checkpoints()
9 months ago
self.check_if_go_die()
self.update_game_window()
self.info.update()
self.brick_group.update()
9 months ago
self.box_group.update()
9 months ago
self.enemy_group.update(self)
self.dying_group.update(self)
self.shell_group.update(self)
self.coin_group.update()
self.box_group.update()
9 months ago
9 months ago
self.draw(surface)
def update_player_position(self):
9 months ago
# x判定
9 months ago
self.player.rect.x += self.player.x_vel
9 months ago
if self.player.rect.x < self.start_x:
self.player.rect.x = self.start_x
elif self.player.rect.right > self.end_x:
self.player.rect.right = self.end_x
9 months ago
self.check_x_collisions()
# y判定
9 months ago
if not self.player.dead:
self.player.rect.y += self.player.y_vel
self.check_y_collisions()
9 months ago
def check_x_collisions(self): # x方向
9 months ago
check_group = pygame.sprite.Group(self.ground_items_group,self.brick_group,self.box_group)
collided_sprite = pygame.sprite.spritecollideany(self.player,check_group) # 检测碰撞
if collided_sprite:
self.adjust_player_x(collided_sprite)
9 months ago
9 months ago
enemy = pygame.sprite.spritecollideany(self.player, self.enemy_group)
if enemy:
self.player.go_die()
shell = pygame.sprite.spritecollideany(self.player, self.shell_group) # 碰撞检测
if shell:
if shell.state == 'slide':
self.player.go_die()
else:
if self.player.rect.x < shell.rect.x: # 龟壳弹开方向以及速度
shell.x_vel = 10
shell.rect.x += 40
shell.direction = 1
else:
shell.x_vel = -10
shell.rect.x -= 40
shell.direction = 0
shell.state = 'slide'
9 months ago
9 months ago
def check_y_collisions(self): # y方向
9 months ago
ground_item = pygame.sprite.spritecollideany(self.player,self.ground_items_group)
brick = pygame.sprite.spritecollideany(self.player, self.brick_group)
box = pygame.sprite.spritecollideany(self.player, self.box_group)
enemy = pygame.sprite.spritecollideany(self.player, self.enemy_group)
if brick and box: # 判断离哪个砖块进哪个顶起
to_brick = abs(self.player.rect.centerx - brick.rect.centerx)
to_box = abs(self.player.rect.centerx - box.rect.centerx)
if to_brick > to_box:
brick = None
else:
box = None
if ground_item:
self.adjust_player_y(ground_item)
elif brick:
self.adjust_player_y(brick)
elif box:
self.adjust_player_y(box)
elif enemy:
self.enemy_group.remove(enemy)
if enemy.name == 'koopa':
self.shell_group.add(enemy) # 龟壳状态进龟壳组
else:
self.dying_group.add(enemy) # 由敌人组 → 死亡组
if self.player.y_vel < 0:
how = 'bumped'
else:
how = 'trampled'
self.player.state = 'jump'
self.player.rect.bottom = enemy.rect.top
self.player.y_vel = self.player.jump_vel * 0.8 # 力道
enemy.go_die(how)
9 months ago
self.check_will_fall(self.player) # 坠落检测
def adjust_player_x(self,sprite):
if self.player.rect.x < sprite.rect.x:
self.player.rect.right = sprite.rect.left # 重置位置为最左边
else:
self.player.rect.left = sprite.rect.right
self.player.x_vel = 0
def adjust_player_y(self,sprite):
if self.player.rect.bottom < sprite.rect.bottom:
self.player.y_vel = 0
self.player.rect.bottom = sprite.rect.top
self.player.state = 'walk'
else:
self.player.y_vel = 7
self.player.rect.top = sprite.rect.bottom
self.player.state = 'fall'
9 months ago
if sprite.name == 'box':
if sprite.state == 'rest':
sprite.go_bumped()
if sprite.name == 'brick':
if sprite.state == 'rest':
sprite.go_bumped()
9 months ago
def check_will_fall(self,sprite):
sprite.rect.y += 1 # 下落一个像素
9 months ago
check_group = pygame.sprite.Group(self.ground_items_group,self.brick_group,self.box_group) # 检测是否碰撞
collided_sprite = pygame.sprite.spritecollideany(sprite,check_group)
9 months ago
if not collided_sprite and sprite.state != 'jump': # 如果没有或者处于跳起则不坠落
9 months ago
sprite.state = 'fall'
sprite.rect.y -= 1
9 months ago
9 months ago
def update_game_window(self):
third = self.game_window.x + self.game_window.width/3
if self.player.x_vel > 0 and self.player.rect.centerx > third and self.game_window.right < self.end_x: # 判断移动
self.game_window.x += self.player.x_vel # 用窗口更新代替主角移动
self.start_x = self.game_window.x
9 months ago
def draw(self, surface):
9 months ago
self.game_ground.blit(self.background,self.game_window,self.game_window)
self.game_ground.blit(self.player.image,self.player.rect) # 将背景与人物化境
9 months ago
self.brick_group.draw(self.game_ground)
9 months ago
self.box_group.draw(self.game_ground)
9 months ago
self.enemy_group.draw(self.game_ground)
self.dying_group.draw(self.game_ground)
self.shell_group.draw(self.game_ground)
self.coin_group.draw(self.game_ground)
self.powerup_group.draw(self.game_ground)
9 months ago
9 months ago
surface.blit(self.game_ground,(0,0), self.game_window) # 渲染
9 months ago
self.info.draw(surface)
9 months ago
def check_checkpoints(self):
checkpoint = pygame.sprite.spritecollideany(self.player,self.checkpoint_group)
if checkpoint:
if checkpoint.checkpoint_type == 0: # checkpoint for enemy appearance # 如果检查点类型为0 释放对应敌人
self.enemy_group.add(self.enemy_group_dict[str(checkpoint.enemy_groupid)]) # 一旦某个点被触发就把对应敌人放入此组
checkpoint.kill() # 被触碰后消失
9 months ago
def check_if_go_die(self):
if self.player.rect.y > C.SCREEN_H:
self.player.go_die() # 判断是否掉落屏幕外
def update_game_info(self):
if self.player.dead:
self.game_info['lives'] -= 1
if self.game_info['lives'] == 0:
self.next = 'game_over'
else:
self.next = 'load_screen'