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.

194 lines
7.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from ..components import info
import pygame
from .. import tools, setup
from .. import constants as C
from .. components import player,stuff,brick,box,enemy
import os
import json
class Level:
def start(self,game_info):
self.game_info = game_info
self.finished = False
self.next = 'game_over'
self.info = info.Info('level',self.game_info)
self.load_map_data()
self.setup_background()
self.setup_start_positions()
self.setup_player()
self.setup_ground_items()
self.setup_bricks_and_boxes()
self.setup_enemies()
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)
def setup_background(self):
self.image_name = self.map_data['image_name']
self.background = setup.GRAPHICS[self.image_name]
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()
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]
def setup_player(self):
self.player = player.Player('mario')
self.player.rect.x = self.game_window.x + self.player_x
self.player.rect.bottom = self.player_y
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))
def setup_bricks_and_boxes(self):
self.brick_group = pygame.sprite.Group()
self.box_group = pygame.sprite.Group()
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']
if 'brick_num' in brick_data:
#TODO Batch bricks
pass
else:
self.brick_group.add(brick.Brick(x,y,brick_type))
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']
self.brick_group.add(box.Box(x, y, box_type))
def setup_enemies(self):
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
def update(self, surface, keys):
self.current_time = pygame.time.get_ticks()
self.player.update(keys)
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()
self.check_if_go_die()
self.update_game_window()
self.info.update()
self.brick_group.update()
self.box_group.update()
for enemy_group in self.enemy_group_dict.values():
enemy_group.update()
self.draw(surface)
def update_player_position(self):
# x判定
self.player.rect.x += self.player.x_vel
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
self.check_x_collisions()
# y判定
self.player.rect.y += self.player.y_vel
self.check_y_collisions()
def check_x_collisions(self): # x方向
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)
def check_y_collisions(self): # y方向
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_y( collided_sprite)
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'
def check_will_fall(self,sprite):
sprite.rect.y += 1 # 下落一个像素
check_group = pygame.sprite.Group(self.ground_items_group,self.brick_group,self.box_group) # 检测是否碰撞
collided_sprite = pygame.sprite.spritecollideany(sprite,check_group)
if not collided_sprite and sprite.state != 'jump' : # 如果没有或者处于跳起则不坠落
sprite.state = 'fall'
sprite.rect.y -= 1
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
def draw(self, surface):
self.game_ground.blit(self.background,self.game_window,self.game_window)
self.game_ground.blit(self.player.image,self.player.rect) # 将背景与人物化境
self.brick_group.draw(self.game_ground)
self.box_group.draw(self.game_ground)
for enemy_group in self.enemy_group_dict.values():
enemy_group.draw(self.game_ground)
surface.blit(self.game_ground,(0,0), self.game_window) # 渲染
self.info.draw(surface)
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'