Started writing new level creation
parent
fd29b7f1df
commit
e53c1084df
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"level": {
|
||||
"block_size": [
|
||||
12,
|
||||
12
|
||||
],
|
||||
"level_size": [
|
||||
71,
|
||||
40
|
||||
]
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
|
||||
#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
|
||||
#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
|
||||
#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,x,x,x,x,x,x,x,x,x,,,,,,,,,,,,,,,,,D,,,#
|
||||
#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,x,x,x,x,x,x,x,x,x,,,,,,,,,,,,,,,,,,,,#
|
||||
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#
|
||||
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#
|
||||
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#
|
||||
|
@ -39,3 +39,4 @@
|
|||
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#
|
||||
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#
|
||||
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#
|
||||
3,3,id=HEBEL
|
Can't render this file because it has a wrong number of fields in line 42.
|
|
@ -93,7 +93,7 @@
|
|||
"id": "tutorial_block_full",
|
||||
"subsheets": [
|
||||
{
|
||||
"id": "1",
|
||||
"id": "on",
|
||||
"delays": [
|
||||
1
|
||||
],
|
||||
|
@ -101,7 +101,7 @@
|
|||
"height": 16
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"id": "off",
|
||||
"delays": [
|
||||
1
|
||||
],
|
||||
|
@ -146,5 +146,153 @@
|
|||
"height": 12
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "castle_block_wall_left",
|
||||
"subsheets": [
|
||||
{
|
||||
"id": "1",
|
||||
"delays": [
|
||||
1
|
||||
],
|
||||
"width": 12,
|
||||
"height": 12
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"delays": [
|
||||
1
|
||||
],
|
||||
"width": 12,
|
||||
"height": 12
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"delays": [
|
||||
1
|
||||
],
|
||||
"width": 12,
|
||||
"height": 12
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "castle_block_wall_right",
|
||||
"subsheets": [
|
||||
{
|
||||
"id": "1",
|
||||
"delays": [
|
||||
1
|
||||
],
|
||||
"width": 12,
|
||||
"height": 12
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"delays": [
|
||||
1
|
||||
],
|
||||
"width": 12,
|
||||
"height": 12
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"delays": [
|
||||
1
|
||||
],
|
||||
"width": 12,
|
||||
"height": 12
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ghost_character",
|
||||
"subsheets": [
|
||||
{
|
||||
"id": "idle",
|
||||
"delays": [
|
||||
40,
|
||||
10
|
||||
],
|
||||
"width": 24,
|
||||
"height": 36
|
||||
},
|
||||
{
|
||||
"id": "walk_l",
|
||||
"delays": [
|
||||
1,
|
||||
1
|
||||
],
|
||||
"width": 24,
|
||||
"height": 36
|
||||
},
|
||||
{
|
||||
"id": "walk_r",
|
||||
"delays": [
|
||||
1,
|
||||
1
|
||||
],
|
||||
"width": 24,
|
||||
"height": 36
|
||||
},
|
||||
{
|
||||
"id": "jump",
|
||||
"delays": [
|
||||
1,
|
||||
1
|
||||
],
|
||||
"width": 24,
|
||||
"height": 36
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "test_1",
|
||||
"subsheets": [
|
||||
{
|
||||
"id": "walk_l",
|
||||
"delays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
1
|
||||
],
|
||||
"width": 16,
|
||||
"height": 16
|
||||
},
|
||||
{
|
||||
"id": "idle",
|
||||
"delays": [
|
||||
1,
|
||||
1,
|
||||
3,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"width": 16,
|
||||
"height": 16
|
||||
},
|
||||
{
|
||||
"id": "walk_r",
|
||||
"delays": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"width": 16,
|
||||
"height": 16
|
||||
},
|
||||
{
|
||||
"id": "other_test",
|
||||
"delays": [
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"width": 16,
|
||||
"height": 16
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,4 +1,5 @@
|
|||
LEVEL_SIZE = (71, 40)
|
||||
from physics import ConstantsParser
|
||||
|
||||
|
||||
|
||||
class Level:
|
||||
|
@ -15,13 +16,13 @@ class Level:
|
|||
tiles = []
|
||||
|
||||
for line_number, line in enumerate(csv_grid):
|
||||
if line_number <= LEVEL_SIZE[1]:
|
||||
if line_number <= ConstantsParser.CONFIG.level_size[1]:
|
||||
tiles.append([])
|
||||
for item_number, item in enumerate(line):
|
||||
if item_number <= LEVEL_SIZE[0]:
|
||||
if item_number <= ConstantsParser.CONFIG.level_size[0]:
|
||||
tiles[line_number].append({'name': item})
|
||||
else:
|
||||
print('Level is too wide:', item_number, '>', LEVEL_SIZE[0])
|
||||
print('Level is too wide:', item_number, '>', ConstantsParser.CONFIG.level_size[0])
|
||||
break
|
||||
|
||||
elif line[0] != '':
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
from level.elements.StaticLevelElement import StaticLevelElement
|
||||
from sprite.Spritesheet import Spritesheet
|
||||
|
||||
|
||||
class BlockElement(StaticLevelElement):
|
||||
def __init__(self, spritesheet: Spritesheet):
|
||||
super().__init__(spritesheet)
|
|
@ -0,0 +1,20 @@
|
|||
from level.Level import Level
|
||||
from level.elements.InputLevelElement import InputLevelElement
|
||||
from physics.SpriteManager import SpriteManager
|
||||
from physics.TickData import TickData
|
||||
from sprite.SpritesheetManager import SpritesheetManager
|
||||
|
||||
|
||||
class ButtonInputLevelElement(InputLevelElement):
|
||||
|
||||
def load(self, sprite_manager: SpriteManager, spritesheet_manager: SpritesheetManager, level: Level):
|
||||
name = self.tile['name']
|
||||
position = self.tile['position']
|
||||
|
||||
self.spritesheet = spritesheet_manager.get_sheet('pressureplate')
|
||||
self.set_animation_state('on' if self.emitter_state else 'off')
|
||||
self.position_scale.position = position
|
||||
|
||||
def tick(self, tick_data: TickData):
|
||||
collisions = self.get_collides_with()
|
||||
print(collisions)
|
|
@ -1,14 +0,0 @@
|
|||
from level.elements.StaticLevelElement import StaticLevelElement
|
||||
from sprite.Spritesheet import Spritesheet
|
||||
|
||||
|
||||
class DoorElement(StaticLevelElement):
|
||||
def __init__(self, spritesheet: Spritesheet, id : str, requires : list[str]):
|
||||
super().__init__(spritesheet)
|
||||
self.id = id
|
||||
self.requires = requires
|
||||
|
||||
def openDoor(self):
|
||||
pass
|
||||
def closeDoor(self):
|
||||
pass
|
|
@ -1,8 +0,0 @@
|
|||
from level.elements.DoorElement import DoorElement
|
||||
from sprite.Spritesheet import Spritesheet
|
||||
|
||||
|
||||
class GateElement(DoorElement):
|
||||
|
||||
def __int__(self, spritesheet: Spritesheet, id : str, requires : list[str]):
|
||||
super().__int__(spritesheet, id, requires)
|
|
@ -1,7 +0,0 @@
|
|||
from level.elements.DoorElement import DoorElement
|
||||
from sprite.Spritesheet import Spritesheet
|
||||
|
||||
|
||||
class GoalDoorElement(DoorElement):
|
||||
def __int__(self, spritesheet: Spritesheet, id : str, requires : list[str]):
|
||||
super().__int__(spritesheet, id, requires)
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
from abc import ABC
|
||||
|
||||
from level.elements.StaticLevelElement import StaticLevelElement
|
||||
|
||||
|
||||
class InputLevelElement(StaticLevelElement, ABC):
|
||||
def __init__(self, tile: dict, loaded_level):
|
||||
super().__init__(tile, loaded_level)
|
||||
|
||||
if 'emitter_state' in tile:
|
||||
self.emitter_state = tile['emitter_state'] == 'true'
|
||||
else:
|
||||
self.emitter_state = False
|
|
@ -1,12 +0,0 @@
|
|||
from level.elements.StaticLevelElement import StaticLevelElement
|
||||
from sprite.Spritesheet import Spritesheet
|
||||
|
||||
|
||||
class InteractableElement(StaticLevelElement):
|
||||
def __init__(self, spritesheet: Spritesheet, block_id: str):
|
||||
super().__init__(spritesheet)
|
||||
self.block_id = block_id
|
||||
self.element = []
|
||||
|
||||
def connect_element(self, element: StaticLevelElement):
|
||||
self.element.append(element)
|
|
@ -0,0 +1,20 @@
|
|||
from abc import abstractmethod
|
||||
|
||||
from level.Level import Level
|
||||
from physics.SpriteManager import SpriteManager
|
||||
from sprite.SpritesheetManager import SpritesheetManager
|
||||
|
||||
|
||||
class LevelElement:
|
||||
def __init__(self, tile: dict, loaded_level):
|
||||
self.tile = tile
|
||||
self.loaded_level = loaded_level
|
||||
self.sprites = []
|
||||
|
||||
@abstractmethod
|
||||
def load(self, sprite_manager: SpriteManager, spritesheet_manager: SpritesheetManager, level: Level):
|
||||
pass
|
||||
|
||||
def destroy(self, sprite_manager: SpriteManager):
|
||||
for sprite in self.sprites:
|
||||
sprite_manager.remove_ui_element(sprite)
|
|
@ -1,16 +1,17 @@
|
|||
import random
|
||||
|
||||
from level.Level import Level
|
||||
from level.LevelElementSymbols import LevelElementSymbols
|
||||
from level.elements.BlockElement import BlockElement
|
||||
from level.elements.GateElement import GateElement
|
||||
from level.elements.GoalDoorElement import GoalDoorElement
|
||||
from level.elements.InteractableElement import InteractableElement
|
||||
from level.elements.StaticLevelElement import StaticLevelElement
|
||||
from level.elements.ButtonInputLevelElement import ButtonInputLevelElement
|
||||
from level.elements.SimpleBlockLevelElement import SimpleBlockLevelElement
|
||||
from physics import ConstantsParser
|
||||
from physics.SpriteManager import SpriteManager, DrawLayers
|
||||
from sprite.SpritesheetManager import SpritesheetManager
|
||||
|
||||
BLOCK_SIZE = (12, 12)
|
||||
TILES = {
|
||||
'#': SimpleBlockLevelElement,
|
||||
'L': ButtonInputLevelElement, # TODO
|
||||
'P': ButtonInputLevelElement
|
||||
}
|
||||
|
||||
|
||||
class LoadedLevel:
|
||||
|
@ -20,53 +21,21 @@ class LoadedLevel:
|
|||
self.blocks = []
|
||||
|
||||
def load_level(self, level: Level):
|
||||
requires_dict: dict[str, list[StaticLevelElement]] = {}
|
||||
for row_number, row in enumerate(level.tiles):
|
||||
for tile_number, tile in enumerate(row):
|
||||
position = (tile_number * BLOCK_SIZE[0], row_number * BLOCK_SIZE[1])
|
||||
position = (tile_number * ConstantsParser.CONFIG.block_size[0],
|
||||
row_number * ConstantsParser.CONFIG.block_size[1])
|
||||
tile['position'] = position
|
||||
|
||||
tile_element = LevelElementSymbols.dict[tile['name']]
|
||||
name = tile['name']
|
||||
if name in TILES:
|
||||
element = TILES[name](tile, self)
|
||||
self.blocks.append(element)
|
||||
self.sprite_manager.add_ui_element(DrawLayers.OBJECTS, element)
|
||||
element.load(self.sprite_manager, self.spritesheet_manager, level)
|
||||
|
||||
sprite = None
|
||||
|
||||
if tile_element in LevelElementSymbols.BLOCKS_LIST:
|
||||
spritesheet = self.spritesheet_manager.get_sheet(level.theme + tile_element['sprite_id'])
|
||||
sprite = BlockElement(spritesheet)
|
||||
sprite.set_animation_state(str(random.randint(1, 3)))
|
||||
sprite.position_scale.position = position
|
||||
|
||||
elif tile_element == LevelElementSymbols.GOAL_DOOR:
|
||||
spritesheet = self.spritesheet_manager.get_sheet(tile_element['sprite_id'])
|
||||
sprite = GoalDoorElement(spritesheet, tile['id'], tile['requires'])
|
||||
sprite.set_animation_state('closed')
|
||||
sprite.position_scale.position = position
|
||||
for required in tile['requires']:
|
||||
requires_dict[required] = requires_dict.get(required, []).append(sprite)
|
||||
|
||||
elif tile_element == LevelElementSymbols.GATE:
|
||||
spritesheet = self.spritesheet_manager.get_sheet(tile_element['sprite_id'])
|
||||
sprite = GateElement(spritesheet, tile['id'], tile['requires'])
|
||||
sprite.set_animation_state('closed')
|
||||
sprite.position_scale.position = position
|
||||
for required in tile['requires']:
|
||||
requires_dict[required] = requires_dict.get(required, []).append(sprite)
|
||||
|
||||
elif tile_element in LevelElementSymbols.INTERACTABLE_LIST:
|
||||
spritesheet = self.spritesheet_manager.get_sheet(tile_element['sprite_id'])
|
||||
sprite = InteractableElement(spritesheet, tile['id'])
|
||||
sprite.set_animation_state('on')
|
||||
sprite.position_scale.position = position
|
||||
|
||||
# tile['id'], tile['requirements']
|
||||
|
||||
if sprite is not None:
|
||||
self.blocks.append(sprite)
|
||||
self.sprite_manager.add_ui_element(DrawLayers.OBJECTS, sprite)
|
||||
|
||||
for block in self.blocks:
|
||||
if isinstance(block, InteractableElement):
|
||||
for requirement in requires_dict:
|
||||
block.connect_element(requirement)
|
||||
elif not name == '':
|
||||
print(f"Unknown tile: {name}")
|
||||
|
||||
def destroy_level(self):
|
||||
for block in self.blocks:
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import random
|
||||
|
||||
from level.Level import Level
|
||||
from level.elements.StaticLevelElement import StaticLevelElement
|
||||
from physics.SpriteManager import SpriteManager
|
||||
from sprite.SpritesheetManager import SpritesheetManager
|
||||
|
||||
BLOCK_TYPES = {
|
||||
'#': 'block_full'
|
||||
}
|
||||
|
||||
|
||||
class SimpleBlockLevelElement(StaticLevelElement):
|
||||
def __init__(self, tile: dict, loaded_level):
|
||||
super().__init__(tile, loaded_level)
|
||||
|
||||
def load(self, sprite_manager: SpriteManager, spritesheet_manager: SpritesheetManager, level: Level):
|
||||
name = self.tile['name']
|
||||
position = self.tile['position']
|
||||
block_type = BLOCK_TYPES[name]
|
||||
|
||||
self.spritesheet = spritesheet_manager.get_sheet(level.theme + '_' + block_type)
|
||||
self.set_animation_state(str(random.randint(1, 3)))
|
||||
self.position_scale.position = position
|
|
@ -1,7 +1,16 @@
|
|||
from sprite.Spritesheet import Spritesheet
|
||||
import uuid
|
||||
from abc import ABC
|
||||
|
||||
from level.elements.LevelElement import LevelElement
|
||||
from sprite.StaticSprite import StaticSprite
|
||||
|
||||
|
||||
class StaticLevelElement(StaticSprite):
|
||||
def __init__(self, spritesheet: Spritesheet):
|
||||
super().__init__(spritesheet)
|
||||
class StaticLevelElement(StaticSprite, LevelElement, ABC):
|
||||
def __init__(self, tile: dict, loaded_level):
|
||||
StaticSprite.__init__(self)
|
||||
LevelElement.__init__(self, tile, loaded_level)
|
||||
|
||||
if 'id' in tile:
|
||||
self.id = tile['id']
|
||||
else:
|
||||
self.id = uuid.uuid4()
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import json
|
||||
|
||||
|
||||
class ConstantsParser:
|
||||
def __init__(self, file: str):
|
||||
parsed = json.load(open(file))
|
||||
self.level_size = (parsed['level']['level_size'][0], parsed['level']['level_size'][1])
|
||||
self.block_size = (parsed['level']['block_size'][0], parsed['level']['block_size'][1])
|
||||
|
||||
|
||||
CONFIG = ConstantsParser("data/config/config.json")
|
|
@ -1,3 +1,5 @@
|
|||
from typing import Optional
|
||||
|
||||
from physics.CollisionDirection import CollisionDirection
|
||||
from sprite.Spritesheet import Spritesheet
|
||||
from sprite.StaticSprite import StaticSprite
|
||||
|
@ -5,7 +7,7 @@ from physics.TickData import TickData
|
|||
|
||||
|
||||
class DynamicSprite(StaticSprite):
|
||||
def __init__(self, spritesheet: Spritesheet):
|
||||
def __init__(self, spritesheet: Optional[Spritesheet] = None):
|
||||
super().__init__(spritesheet)
|
||||
|
||||
self.motion = (0, 0)
|
||||
|
|
|
@ -12,11 +12,14 @@ from ui_elements.UiElement import UiElement
|
|||
|
||||
|
||||
class Sprite(UiElement):
|
||||
def __init__(self, spritesheet: Spritesheet):
|
||||
def __init__(self, spritesheet: Optional[Spritesheet] = None):
|
||||
super().__init__()
|
||||
self.spritesheet = spritesheet
|
||||
|
||||
self.animation_state = list(self.spritesheet.animations.keys())[0]
|
||||
if self.spritesheet is not None:
|
||||
self.animation_state = list(self.spritesheet.animations.keys())[0]
|
||||
else:
|
||||
self.animation_state = None
|
||||
self.animation_frame = 0
|
||||
self.animation_delay = 0
|
||||
|
||||
|
@ -43,6 +46,10 @@ class Sprite(UiElement):
|
|||
return None
|
||||
|
||||
def tick(self, tick_data: TickData):
|
||||
if self.spritesheet is None:
|
||||
self.image = None
|
||||
return
|
||||
|
||||
animation = self.spritesheet.animations[self.animation_state]
|
||||
|
||||
if self.animated:
|
||||
|
@ -55,10 +62,15 @@ class Sprite(UiElement):
|
|||
self.image = animation['images'][self.animation_frame % len(animation['images'])]
|
||||
|
||||
def set_animation_state(self, state: str):
|
||||
if self.spritesheet is None:
|
||||
return
|
||||
|
||||
if state in self.spritesheet.animations:
|
||||
self.animation_state = state
|
||||
self.animation_delay = 0
|
||||
self.tick(self.empty_tick_data())
|
||||
else:
|
||||
print('Unknown animation state: ' + state)
|
||||
|
||||
def set_animation_frame(self, frame: int):
|
||||
self.animation_frame = frame
|
||||
|
@ -77,32 +89,3 @@ class Sprite(UiElement):
|
|||
self.image.get_width() * self.position_scale.scale[0],
|
||||
self.image.get_height() * self.position_scale.scale[1]
|
||||
)
|
||||
|
||||
def dump(self, file):
|
||||
# re-attach all the images to a single surface and save it to a file
|
||||
width = 0
|
||||
height = 0
|
||||
|
||||
for animation in self.spritesheet.animations.values():
|
||||
max_height = 0
|
||||
total_width = 0
|
||||
for image in animation['images']:
|
||||
total_width += image.get_width()
|
||||
max_height = max(max_height, image.get_height())
|
||||
width = max(width, total_width)
|
||||
height += max_height
|
||||
|
||||
sheet = pygame.Surface((width, height))
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
for animation in self.spritesheet.animations.values():
|
||||
max_height = 0
|
||||
for image in animation['images']:
|
||||
sheet.blit(image, (x, y))
|
||||
x += image.get_width()
|
||||
max_height = max(max_height, image.get_height())
|
||||
y += max_height
|
||||
x = 0
|
||||
|
||||
pygame.image.save(sheet, file)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
from typing import Optional
|
||||
|
||||
from sprite.Sprite import Sprite
|
||||
from sprite.Spritesheet import Spritesheet
|
||||
|
||||
|
||||
class StaticSprite(Sprite):
|
||||
def __init__(self, spritesheet: Spritesheet):
|
||||
def __init__(self, spritesheet: Optional[Spritesheet] = None):
|
||||
super().__init__(spritesheet)
|
||||
|
||||
def collides_with(self, collider: 'StaticSprite', tolerance: float = 0.0):
|
||||
|
|
Loading…
Reference in New Issue