Merge pull request 'bfs' (#19) from bfs into master
Reviewed-on: s464965/WMICraft#19
120
algorithms/bfs.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from common.constants import ACTION, Direction, ROWS, COLUMNS
|
||||||
|
|
||||||
|
|
||||||
|
class State:
|
||||||
|
def __init__(self, row, column, direction):
|
||||||
|
self.row = row
|
||||||
|
self.column = column
|
||||||
|
self.direction = direction
|
||||||
|
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
def __init__(self, state, parent=None, action=None):
|
||||||
|
self.state = state
|
||||||
|
self.parent = parent
|
||||||
|
self.action = action
|
||||||
|
|
||||||
|
|
||||||
|
def goal_test(goal_list, state: State):
|
||||||
|
if (state.row, state.column) in goal_list:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_successors(state: State, map):
|
||||||
|
successors = list()
|
||||||
|
|
||||||
|
state_left = State(state.row, state.column, state.direction.left())
|
||||||
|
successors.append((ACTION.get("rotate_left"), state_left))
|
||||||
|
|
||||||
|
state_right = State(state.row, state.column, state.direction.right())
|
||||||
|
successors.append((ACTION.get("rotate_right"), state_right))
|
||||||
|
|
||||||
|
target = go(state.row, state.column, state.direction)
|
||||||
|
|
||||||
|
if is_valid_move(map, target[0], target[1]):
|
||||||
|
state_go = State(target[0], target[1], state.direction)
|
||||||
|
successors.append((ACTION.get("go"), state_go))
|
||||||
|
|
||||||
|
return successors
|
||||||
|
|
||||||
|
|
||||||
|
def graphsearch(initial_state: State, map, goal_list, fringe: List[Node] = None, explored: List[Node] = None):
|
||||||
|
# fringe and explored initialization
|
||||||
|
if fringe is None:
|
||||||
|
fringe = list()
|
||||||
|
if explored is None:
|
||||||
|
explored = list()
|
||||||
|
explored_states = set()
|
||||||
|
fringe_states = set()
|
||||||
|
|
||||||
|
# root Node
|
||||||
|
fringe.append(Node(initial_state))
|
||||||
|
fringe_states.add((initial_state.row, initial_state.column, initial_state.direction))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# fringe empty -> solution not found
|
||||||
|
if not any(fringe):
|
||||||
|
print("Brak rozwiazania")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# get first element from fringe
|
||||||
|
element = fringe.pop(0)
|
||||||
|
fringe_states.remove((element.state.row, element.state.column, element.state.direction))
|
||||||
|
|
||||||
|
# if solution was found, prepare and return actions sequence
|
||||||
|
if goal_test(goal_list, element.state):
|
||||||
|
actions_sequence = [element.action]
|
||||||
|
parent = element.parent
|
||||||
|
|
||||||
|
while parent is not None:
|
||||||
|
# root's action will be None, don't add it
|
||||||
|
if parent.action is not None:
|
||||||
|
actions_sequence.append(parent.action)
|
||||||
|
parent = parent.parent
|
||||||
|
|
||||||
|
actions_sequence.reverse()
|
||||||
|
return actions_sequence
|
||||||
|
|
||||||
|
# add current node to explored (prevents infinite cycles)
|
||||||
|
explored.append(element)
|
||||||
|
explored_states.add((element.state.row, element.state.column, element.state.direction))
|
||||||
|
|
||||||
|
# loop through every possible next action
|
||||||
|
for successor in get_successors(element.state, map):
|
||||||
|
|
||||||
|
# make sure not to fall into a cycle
|
||||||
|
successor_state = (successor[1].row, successor[1].column, successor[1].direction)
|
||||||
|
if successor_state not in fringe_states and successor_state not in explored_states:
|
||||||
|
# create new Node and add it at the end of fringe
|
||||||
|
new_node = Node(state=successor[1],
|
||||||
|
parent=element,
|
||||||
|
action=successor[0])
|
||||||
|
fringe.append(new_node)
|
||||||
|
fringe_states.add((new_node.state.row, new_node.state.column, new_node.state.direction))
|
||||||
|
|
||||||
|
|
||||||
|
# TEMPORARY METHOD
|
||||||
|
def go(row, column, direction):
|
||||||
|
target = tuple()
|
||||||
|
|
||||||
|
if direction == Direction.RIGHT:
|
||||||
|
target = row, column + 1
|
||||||
|
elif direction == Direction.LEFT:
|
||||||
|
target = row, column - 1
|
||||||
|
elif direction == Direction.UP:
|
||||||
|
target = row - 1, column
|
||||||
|
elif direction == Direction.DOWN:
|
||||||
|
target = row + 1, column
|
||||||
|
|
||||||
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid_move(map, target_row, target_column):
|
||||||
|
if 0 <= target_row < ROWS and 0 <= target_column < COLUMNS and map[target_row][target_column] == ' ':
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
@ -1,35 +1,63 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
GAME_TITLE = 'WMICraft'
|
GAME_TITLE = 'WMICraft'
|
||||||
WINDOW_HEIGHT = 800
|
WINDOW_HEIGHT = 800
|
||||||
WINDOW_WIDTH = 1360
|
WINDOW_WIDTH = 1360
|
||||||
|
FPS_COUNT = 60
|
||||||
|
TURN_INTERVAL = 1000
|
||||||
|
|
||||||
GRID_CELL_PADDING = 5
|
GRID_CELL_PADDING = 5
|
||||||
GRID_CELL_WIDTH = 36
|
GRID_CELL_SIZE = 36
|
||||||
GRID_CELL_HEIGHT = 36
|
|
||||||
ROWS = 19
|
ROWS = 19
|
||||||
COLUMNS = 24
|
COLUMNS = 24
|
||||||
|
|
||||||
BORDER_WIDTH = 10
|
BORDER_WIDTH = 10
|
||||||
BORDER_RADIUS = 5
|
BORDER_RADIUS = 5
|
||||||
FPS_COUNT = 60
|
|
||||||
KNIGHTS_SPAWN_WIDTH = 4
|
KNIGHTS_SPAWN_WIDTH = 4
|
||||||
KNIGHTS_SPAWN_HEIGHT = 7
|
KNIGHTS_SPAWN_HEIGHT = 7
|
||||||
LEFT_KNIGHTS_SPAWN_FIRST_ROW = 6
|
LEFT_KNIGHTS_SPAWN_FIRST_ROW = 6
|
||||||
LEFT_KNIGHTS_SPAWN_FIRST_COL = 0
|
LEFT_KNIGHTS_SPAWN_FIRST_COL = 0
|
||||||
RIGHT_KNIGHTS_SPAWN_FIRST_ROW = 6
|
RIGHT_KNIGHTS_SPAWN_FIRST_ROW = 6
|
||||||
RIGHT_KNIGHTS_SPAWN_FIRST_COL = 20
|
RIGHT_KNIGHTS_SPAWN_FIRST_COL = 20
|
||||||
NBR_OF_WATER = 10
|
|
||||||
NBR_OF_TREES = 16
|
|
||||||
|
|
||||||
CASTLE_SPAWN_WIDTH = 6
|
CASTLE_SPAWN_WIDTH = 6
|
||||||
CASTLE_SPAWN_HEIGHT = 5
|
CASTLE_SPAWN_HEIGHT = 5
|
||||||
CASTLE_SPAWN_FIRST_ROW = 7
|
CASTLE_SPAWN_FIRST_ROW = 7
|
||||||
CASTLE_SPAWN_FIRST_COL = 9
|
CASTLE_SPAWN_FIRST_COL = 9
|
||||||
|
|
||||||
|
NBR_OF_WATER = 16
|
||||||
|
NBR_OF_TREES = 20
|
||||||
|
NBR_OF_MONSTERS = 2
|
||||||
|
|
||||||
TILES = [
|
TILES = [
|
||||||
'grass1.png',
|
'grass1.png',
|
||||||
'grass2.png',
|
'grass2.png',
|
||||||
'grass3.png',
|
'grass3.png',
|
||||||
# 'grass4.png',
|
'grass4.png',
|
||||||
# 'grass5.png',
|
|
||||||
# 'grass6.png',
|
|
||||||
'sand.png',
|
'sand.png',
|
||||||
'water.png',
|
'water.png',
|
||||||
'grass_with_tree.jpg',
|
'grass_with_tree.jpg',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Direction(Enum):
|
||||||
|
UP = 0
|
||||||
|
RIGHT = 1
|
||||||
|
DOWN = 2
|
||||||
|
LEFT = 3
|
||||||
|
|
||||||
|
def right(self):
|
||||||
|
v = (self.value + 1) % 4
|
||||||
|
return Direction(v)
|
||||||
|
|
||||||
|
def left(self):
|
||||||
|
v = (self.value - 1) % 4
|
||||||
|
return Direction(v)
|
||||||
|
|
||||||
|
|
||||||
|
ACTION = {
|
||||||
|
"rotate_left": -1,
|
||||||
|
"rotate_right": 1,
|
||||||
|
"go": 0,
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import pygame
|
import pygame
|
||||||
|
from common.constants import GRID_CELL_PADDING, GRID_CELL_SIZE, COLUMNS, ROWS
|
||||||
|
|
||||||
|
|
||||||
def draw_text(text, color, surface, x, y, text_size=30, is_bold=False):
|
def draw_text(text, color, surface, x, y, text_size=30, is_bold=False):
|
||||||
@ -10,3 +11,37 @@ def draw_text(text, color, surface, x, y, text_size=30, is_bold=False):
|
|||||||
textrect = textobj.get_rect()
|
textrect = textobj.get_rect()
|
||||||
textrect.topleft = (x, y)
|
textrect.topleft = (x, y)
|
||||||
surface.blit(textobj, textrect)
|
surface.blit(textobj, textrect)
|
||||||
|
|
||||||
|
|
||||||
|
def print_numbers():
|
||||||
|
display_surface = pygame.display.get_surface()
|
||||||
|
font = pygame.font.SysFont('Arial', 16)
|
||||||
|
|
||||||
|
for row_index in range(ROWS):
|
||||||
|
for col_index in range(COLUMNS):
|
||||||
|
x = (GRID_CELL_PADDING + GRID_CELL_SIZE) * col_index + GRID_CELL_PADDING + 7
|
||||||
|
y = (GRID_CELL_PADDING + GRID_CELL_SIZE) * row_index + GRID_CELL_PADDING + 16
|
||||||
|
display_surface.blit(font.render(f'[{col_index}, {row_index}]', True, (255, 0, 0)), (x, y))
|
||||||
|
pygame.display.update()
|
||||||
|
|
||||||
|
|
||||||
|
# parse array index to screen x or y coordinate
|
||||||
|
def parse_cord(cord):
|
||||||
|
return (GRID_CELL_PADDING + GRID_CELL_SIZE) * cord + GRID_CELL_PADDING + 7
|
||||||
|
|
||||||
|
|
||||||
|
def castle_neighbors(map, castle_bottom_right_row, castle_bottom_right_col):
|
||||||
|
neighbors = []
|
||||||
|
for row_add in range(-2, 2):
|
||||||
|
new_row = castle_bottom_right_row + row_add
|
||||||
|
if 0 <= new_row <= len(map) - 1:
|
||||||
|
for col_add in range(-2, 2):
|
||||||
|
new_col = castle_bottom_right_col + col_add
|
||||||
|
if 0 <= new_col <= len(map) - 1:
|
||||||
|
if (new_col == castle_bottom_right_col - 1 and new_row == castle_bottom_right_row - 1) \
|
||||||
|
or (new_col == castle_bottom_right_col and new_row == castle_bottom_right_row - 1) \
|
||||||
|
or (new_col == castle_bottom_right_col - 1 and new_row == castle_bottom_right_row) \
|
||||||
|
or (new_col == castle_bottom_right_col and new_row == castle_bottom_right_row):
|
||||||
|
continue
|
||||||
|
neighbors.append((new_col, new_row))
|
||||||
|
return neighbors
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import pygame
|
|
||||||
|
|
||||||
from logic.exceptions import FieldNotWalkable
|
|
||||||
|
|
||||||
|
|
||||||
class Field(pygame.sprite.Sprite):
|
|
||||||
def __init__(self, texture_path, converted_texture, img, rect, row=0, column=0):
|
|
||||||
super().__init__()
|
|
||||||
self.texture_path = texture_path
|
|
||||||
self.converted_texture = converted_texture
|
|
||||||
self.image = img
|
|
||||||
self.row = row
|
|
||||||
self.column = column
|
|
||||||
self.rect = rect
|
|
||||||
self.busy = False
|
|
||||||
self.busy_detection()
|
|
||||||
|
|
||||||
def busy_detection(self):
|
|
||||||
if self.texture_path == 'water.png' or self.texture_path == 'grass_with_tree.jpg':
|
|
||||||
self.busy = True
|
|
||||||
|
|
||||||
def put_on(self, obj): # ustawia objekt na srodku pola
|
|
||||||
if not self.busy:
|
|
||||||
obj.rect = obj.rect.clamp(self.rect)
|
|
||||||
self.busy = True
|
|
||||||
obj.update()
|
|
||||||
else:
|
|
||||||
raise FieldNotWalkable
|
|
142
logic/game.py
@ -2,19 +2,14 @@ import sys
|
|||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
from common.colors import FONT_DARK, WHITE
|
|
||||||
from common.constants import *
|
from common.constants import *
|
||||||
from common.helpers import draw_text
|
from common.helpers import print_numbers
|
||||||
from logic.knights_queue import KnightsQueue
|
from logic.level import Level
|
||||||
from models.castle import Castle
|
|
||||||
from models.knight import Knight
|
|
||||||
from models.monster import Monster
|
|
||||||
from ui.logs import Logs
|
from ui.logs import Logs
|
||||||
from ui.screens.credits import Credits
|
from ui.screens.credits import Credits
|
||||||
|
from ui.screens.main_menu import MainMenu
|
||||||
from ui.screens.options import Options
|
from ui.screens.options import Options
|
||||||
from ui.stats import Stats
|
from ui.stats import Stats
|
||||||
from .grid import Grid
|
|
||||||
from .spawner import Spawner
|
|
||||||
|
|
||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
@ -26,99 +21,31 @@ class Game:
|
|||||||
self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
|
self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
|
||||||
self.clock = pygame.time.Clock()
|
self.clock = pygame.time.Clock()
|
||||||
|
|
||||||
self.tiles = []
|
|
||||||
for tile_path in TILES:
|
|
||||||
converted_tile = pygame.image.load('resources/textures/' + tile_path).convert_alpha()
|
|
||||||
self.tiles.append((tile_path, converted_tile))
|
|
||||||
|
|
||||||
self.bg = pygame.image.load("./resources/textures/bg.jpg")
|
self.bg = pygame.image.load("./resources/textures/bg.jpg")
|
||||||
self.screens = {'credits': Credits(self.screen, self.clock), 'options': Options(self.screen, self.clock)}
|
self.screens = {'credits': Credits(self.screen, self.clock), 'options': Options(self.screen, self.clock)}
|
||||||
|
|
||||||
click = False
|
self.level = Level(self.screen)
|
||||||
|
|
||||||
def main_menu(self):
|
def main_menu(self):
|
||||||
while True:
|
menu = MainMenu(self.screen, self.clock, self.bg,
|
||||||
self.screen.blit(self.bg, (0, 0))
|
self.game,
|
||||||
|
self.screens['options'].display_screen,
|
||||||
pygame.draw.rect(self.screen, (255, 255, 255), pygame.Rect(800, 100, 400, 500), 0, 5)
|
self.screens['credits'].display_screen)
|
||||||
draw_text('MAIN MENU', FONT_DARK, self.screen, 850, 150, 30, True)
|
menu.display_screen()
|
||||||
|
|
||||||
mx, my = pygame.mouse.get_pos()
|
|
||||||
|
|
||||||
button_1 = pygame.Rect(850, 250, 300, 50)
|
|
||||||
button_2 = pygame.Rect(850, 350, 300, 50)
|
|
||||||
button_3 = pygame.Rect(850, 450, 300, 50)
|
|
||||||
if button_1.collidepoint((mx, my)):
|
|
||||||
if click:
|
|
||||||
self.game()
|
|
||||||
if button_2.collidepoint((mx, my)):
|
|
||||||
if click:
|
|
||||||
self.screens['options'].display_screen()
|
|
||||||
if button_3.collidepoint((mx, my)):
|
|
||||||
if click:
|
|
||||||
self.screens['credits'].display_screen()
|
|
||||||
pygame.draw.rect(self.screen, (0, 191, 255), button_1, 0, 4)
|
|
||||||
draw_text('PLAY', WHITE, self.screen, 870, 255)
|
|
||||||
|
|
||||||
pygame.draw.rect(self.screen, (0, 191, 255), button_2, 0, 4)
|
|
||||||
draw_text('OPTIONS', WHITE, self.screen, 870, 355)
|
|
||||||
|
|
||||||
pygame.draw.rect(self.screen, (0, 191, 255), button_3, 0, 4)
|
|
||||||
draw_text('CREDITS', WHITE, self.screen, 870, 455)
|
|
||||||
|
|
||||||
click = False
|
|
||||||
for event in pygame.event.get():
|
|
||||||
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.MOUSEBUTTONDOWN:
|
|
||||||
if event.button == 1:
|
|
||||||
click = True
|
|
||||||
|
|
||||||
pygame.display.update()
|
|
||||||
self.clock.tick(60)
|
|
||||||
|
|
||||||
def game(self):
|
def game(self):
|
||||||
running = True
|
|
||||||
grid = Grid(self.tiles)
|
|
||||||
stats = Stats()
|
stats = Stats()
|
||||||
logs = Logs()
|
logs = Logs()
|
||||||
|
|
||||||
knights_sprite_group = pygame.sprite.Group()
|
# setup clock for rounds
|
||||||
monsters_sprite_group = pygame.sprite.Group()
|
NEXT_TURN = pygame.USEREVENT + 1
|
||||||
castle_sprite_group = pygame.sprite.Group()
|
pygame.time.set_timer(NEXT_TURN, TURN_INTERVAL)
|
||||||
|
|
||||||
knights_left = self.generate_knights_team(knights_sprite_group)
|
# create level
|
||||||
knights_right = self.generate_knights_team(knights_sprite_group)
|
self.level.create_map()
|
||||||
|
|
||||||
knights_queue = KnightsQueue(knights_left, knights_right)
|
|
||||||
|
|
||||||
spawn_left_team = Spawner(grid, knights_left, KNIGHTS_SPAWN_WIDTH, KNIGHTS_SPAWN_HEIGHT,
|
|
||||||
LEFT_KNIGHTS_SPAWN_FIRST_ROW, LEFT_KNIGHTS_SPAWN_FIRST_COL)
|
|
||||||
spawn_right_team = Spawner(grid, knights_right, KNIGHTS_SPAWN_WIDTH, KNIGHTS_SPAWN_HEIGHT,
|
|
||||||
RIGHT_KNIGHTS_SPAWN_FIRST_ROW,
|
|
||||||
RIGHT_KNIGHTS_SPAWN_FIRST_COL)
|
|
||||||
|
|
||||||
spawn_left_team.spawn()
|
|
||||||
spawn_right_team.spawn()
|
|
||||||
|
|
||||||
spawned_monsters = self.generate_monster(monsters_sprite_group)
|
|
||||||
monster_spawn = Spawner(grid, spawned_monsters, spawn_where_possible=True)
|
|
||||||
|
|
||||||
monster_spawn.spawn()
|
|
||||||
|
|
||||||
spawned_castle = self.generate_castle(castle_sprite_group)
|
|
||||||
castle_spawn = Spawner(grid, [spawned_castle], CASTLE_SPAWN_WIDTH, CASTLE_SPAWN_HEIGHT,
|
|
||||||
CASTLE_SPAWN_FIRST_ROW, CASTLE_SPAWN_FIRST_COL)
|
|
||||||
|
|
||||||
castle_spawn.spawn()
|
|
||||||
|
|
||||||
#grid.put_on_tile(0, 0, knights_left[0])
|
|
||||||
|
|
||||||
|
print_numbers_flag = False
|
||||||
|
running = True
|
||||||
while running:
|
while running:
|
||||||
self.screen.blit(self.bg, (0, 0))
|
self.screen.blit(self.bg, (0, 0))
|
||||||
|
|
||||||
@ -129,37 +56,18 @@ class Game:
|
|||||||
if event.type == pygame.KEYDOWN:
|
if event.type == pygame.KEYDOWN:
|
||||||
if event.key == pygame.K_ESCAPE:
|
if event.key == pygame.K_ESCAPE:
|
||||||
running = False
|
running = False
|
||||||
|
if event.key == 110: # clicked n letter on keyboard
|
||||||
|
print_numbers_flag = not print_numbers_flag
|
||||||
|
if event.type == NEXT_TURN: # is called every 'TURN_INTERVAL' milliseconds
|
||||||
|
self.level.handle_turn()
|
||||||
|
|
||||||
grid.update(self.screen)
|
|
||||||
stats.draw(self.screen)
|
stats.draw(self.screen)
|
||||||
logs.draw(self.screen)
|
logs.draw(self.screen)
|
||||||
|
|
||||||
knights_sprite_group.draw(self.screen)
|
self.level.update()
|
||||||
monsters_sprite_group.draw(self.screen)
|
|
||||||
castle_sprite_group.draw(self.screen)
|
if print_numbers_flag:
|
||||||
|
print_numbers()
|
||||||
|
|
||||||
pygame.display.update()
|
pygame.display.update()
|
||||||
self.clock.tick(FPS_COUNT)
|
self.clock.tick(FPS_COUNT)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def generate_knights_team(knights_sprite_group):
|
|
||||||
knights = []
|
|
||||||
for i in range(4):
|
|
||||||
knight = Knight("./resources/textures/knight.png")
|
|
||||||
knights.append(knight)
|
|
||||||
knights_sprite_group.add(knight)
|
|
||||||
return knights
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def generate_monster(monsters_sprite_group):
|
|
||||||
monsters = []
|
|
||||||
for i in range(2):
|
|
||||||
monster = Monster()
|
|
||||||
monsters.append(monster)
|
|
||||||
monsters_sprite_group.add(monster)
|
|
||||||
return monsters
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def generate_castle(castle_sprite_group):
|
|
||||||
castle = Castle()
|
|
||||||
castle_sprite_group.add(castle)
|
|
||||||
return castle
|
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
import random
|
|
||||||
import numpy as np
|
|
||||||
import pygame
|
|
||||||
|
|
||||||
from common.constants import ROWS, COLUMNS, GRID_CELL_PADDING, GRID_CELL_WIDTH, GRID_CELL_HEIGHT, BORDER_WIDTH, \
|
|
||||||
BORDER_RADIUS, NBR_OF_TREES, NBR_OF_WATER
|
|
||||||
from .exceptions import FieldNotWalkable
|
|
||||||
from .field import Field
|
|
||||||
|
|
||||||
|
|
||||||
class Grid:
|
|
||||||
def __init__(self, textures):
|
|
||||||
self.textures = textures
|
|
||||||
self.grid = []
|
|
||||||
self.free_fields = []
|
|
||||||
self.busy_fields = []
|
|
||||||
podkladka = np.zeros((ROWS, COLUMNS))
|
|
||||||
for drzewa in range(0, NBR_OF_TREES):
|
|
||||||
rzad = random.randint(0, ROWS - 1)
|
|
||||||
kolumna = random.randint(0, COLUMNS - 1)
|
|
||||||
if podkladka[rzad][kolumna] == 0:
|
|
||||||
podkladka[rzad][kolumna] = 1
|
|
||||||
else:
|
|
||||||
drzewa = drzewa - 1
|
|
||||||
for i in range(0, NBR_OF_WATER):
|
|
||||||
rzad = random.randint(0, ROWS - 1)
|
|
||||||
kolumna = random.randint(0, COLUMNS - 1)
|
|
||||||
if podkladka[rzad][kolumna] == 0:
|
|
||||||
podkladka[rzad][kolumna] = 2
|
|
||||||
else:
|
|
||||||
drzewa = drzewa - 1
|
|
||||||
|
|
||||||
for row in range(ROWS):
|
|
||||||
self.grid.append([])
|
|
||||||
for column in range(COLUMNS):
|
|
||||||
box_rect = [(GRID_CELL_PADDING + GRID_CELL_WIDTH) * column + GRID_CELL_PADDING + 7,
|
|
||||||
(GRID_CELL_PADDING + GRID_CELL_HEIGHT) * row + GRID_CELL_PADDING + 7,
|
|
||||||
GRID_CELL_WIDTH,
|
|
||||||
GRID_CELL_HEIGHT]
|
|
||||||
if podkladka[row][column] == 1:
|
|
||||||
texture_path, converted_texture = self.textures[-1]
|
|
||||||
elif podkladka[row][column] == 2:
|
|
||||||
texture_path, converted_texture = self.textures[-2]
|
|
||||||
else:
|
|
||||||
texture_path, converted_texture = self.get_random_texture()
|
|
||||||
field = Field(
|
|
||||||
texture_path,
|
|
||||||
converted_texture,
|
|
||||||
pygame.transform.scale(converted_texture,
|
|
||||||
(GRID_CELL_WIDTH,
|
|
||||||
GRID_CELL_HEIGHT)),
|
|
||||||
pygame.Rect(box_rect),
|
|
||||||
row=row,
|
|
||||||
column=column
|
|
||||||
)
|
|
||||||
if field.busy:
|
|
||||||
self.busy_fields.append(field)
|
|
||||||
else:
|
|
||||||
self.free_fields.append(field)
|
|
||||||
|
|
||||||
self.grid[row].append(pygame.sprite.Group(field))
|
|
||||||
|
|
||||||
def update(self, screen):
|
|
||||||
self.draw(screen)
|
|
||||||
|
|
||||||
def get_random_texture(self):
|
|
||||||
texture_index = random.randint(0, len(self.textures) - 3)
|
|
||||||
return self.textures[texture_index]
|
|
||||||
|
|
||||||
def get_tile(self, row, column):
|
|
||||||
return pygame.sprite.Group.sprites(self.grid[row][column])[0] # iteruj kolumny i wiersze od 0
|
|
||||||
|
|
||||||
def put_on_tile(self, row, column, obj): # iteruj kolumny i wiersze od 0
|
|
||||||
try:
|
|
||||||
self.get_tile(row, column).put_on(obj)
|
|
||||||
except FieldNotWalkable:
|
|
||||||
print("Field busy")
|
|
||||||
|
|
||||||
def draw(self, screen):
|
|
||||||
bg_width = (GRID_CELL_PADDING + GRID_CELL_WIDTH) * COLUMNS + BORDER_WIDTH
|
|
||||||
bg_height = (GRID_CELL_PADDING + GRID_CELL_HEIGHT) * ROWS + BORDER_WIDTH
|
|
||||||
pygame.draw.rect(screen, (255, 255, 255), pygame.Rect(5, 5, bg_width, bg_height), 0, BORDER_RADIUS)
|
|
||||||
|
|
||||||
for fields_row in self.grid:
|
|
||||||
for fields in fields_row:
|
|
||||||
fields.draw(screen)
|
|
144
logic/level.py
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from algorithms.bfs import graphsearch, State
|
||||||
|
from common.constants import *
|
||||||
|
from common.helpers import castle_neighbors
|
||||||
|
from logic.knights_queue import KnightsQueue
|
||||||
|
from logic.spawner import Spawner
|
||||||
|
from models.castle import Castle
|
||||||
|
from models.knight import Knight
|
||||||
|
from models.monster import Monster
|
||||||
|
from models.tile import Tile
|
||||||
|
|
||||||
|
|
||||||
|
class Level:
|
||||||
|
def __init__(self, screen):
|
||||||
|
self.screen = screen
|
||||||
|
|
||||||
|
# sprite group setup
|
||||||
|
self.sprites = pygame.sprite.Group()
|
||||||
|
|
||||||
|
self.map = [[' ' for x in range(COLUMNS)] for y in range(ROWS)]
|
||||||
|
|
||||||
|
self.list_knights_blue = []
|
||||||
|
self.list_knights_red = []
|
||||||
|
self.list_monsters = []
|
||||||
|
self.list_castles = []
|
||||||
|
|
||||||
|
self.knights_queue = None
|
||||||
|
|
||||||
|
def create_map(self):
|
||||||
|
self.generate_map()
|
||||||
|
self.setup_base_tiles()
|
||||||
|
self.setup_objects()
|
||||||
|
self.knights_queue = KnightsQueue(self.list_knights_blue, self.list_knights_red)
|
||||||
|
|
||||||
|
def generate_map(self):
|
||||||
|
spawner = Spawner(self.map)
|
||||||
|
spawner.spawn_where_possible(['w' for x in range(NBR_OF_WATER)])
|
||||||
|
spawner.spawn_where_possible(['t' for x in range(NBR_OF_TREES)])
|
||||||
|
|
||||||
|
spawner.spawn_in_area(['k_b' for x in range(4)], LEFT_KNIGHTS_SPAWN_FIRST_ROW, LEFT_KNIGHTS_SPAWN_FIRST_COL,
|
||||||
|
KNIGHTS_SPAWN_WIDTH, KNIGHTS_SPAWN_HEIGHT)
|
||||||
|
spawner.spawn_in_area(['k_r' for x in range(4)], RIGHT_KNIGHTS_SPAWN_FIRST_ROW, RIGHT_KNIGHTS_SPAWN_FIRST_COL,
|
||||||
|
KNIGHTS_SPAWN_WIDTH, KNIGHTS_SPAWN_HEIGHT)
|
||||||
|
|
||||||
|
spawner.spawn_in_area(['c'], CASTLE_SPAWN_FIRST_ROW, CASTLE_SPAWN_FIRST_COL, CASTLE_SPAWN_WIDTH,
|
||||||
|
CASTLE_SPAWN_HEIGHT, 2)
|
||||||
|
|
||||||
|
spawner.spawn_where_possible(['m' for x in range(NBR_OF_MONSTERS)])
|
||||||
|
|
||||||
|
def setup_base_tiles(self):
|
||||||
|
textures = []
|
||||||
|
for texture_path in TILES:
|
||||||
|
converted_texture = pygame.image.load('resources/textures/' + texture_path).convert_alpha()
|
||||||
|
converted_texture = pygame.transform.scale(converted_texture, (40, 40))
|
||||||
|
textures.append((texture_path, converted_texture))
|
||||||
|
|
||||||
|
for row_index, row in enumerate(self.map):
|
||||||
|
for col_index, col in enumerate(row):
|
||||||
|
|
||||||
|
# add base tiles, e.g. water, tree, grass
|
||||||
|
if col == "w":
|
||||||
|
texture_index = 5
|
||||||
|
texture_surface = textures[texture_index][1]
|
||||||
|
Tile((col_index, row_index), texture_surface, self.sprites, 'w')
|
||||||
|
elif col == "t":
|
||||||
|
texture_index = 6
|
||||||
|
texture_surface = textures[texture_index][1]
|
||||||
|
Tile((col_index, row_index), texture_surface, self.sprites, 't')
|
||||||
|
else:
|
||||||
|
texture_index = random.randint(0, 4)
|
||||||
|
texture_surface = textures[texture_index][1]
|
||||||
|
Tile((col_index, row_index), texture_surface, self.sprites)
|
||||||
|
|
||||||
|
def setup_objects(self):
|
||||||
|
castle_count = 0 # TODO: find some smarter method to print castle
|
||||||
|
|
||||||
|
for row_index, row in enumerate(self.map):
|
||||||
|
print(row)
|
||||||
|
for col_index, col in enumerate(row):
|
||||||
|
|
||||||
|
# add objects, e.g. knights, monsters, castle
|
||||||
|
if col == "k_b":
|
||||||
|
knight = Knight((col_index, row_index), self.sprites, "blue")
|
||||||
|
self.map[row_index][col_index] = knight
|
||||||
|
self.list_knights_blue.append(knight)
|
||||||
|
elif col == "k_r":
|
||||||
|
knight = Knight((col_index, row_index), self.sprites, "red")
|
||||||
|
self.map[row_index][col_index] = knight
|
||||||
|
self.list_knights_red.append(knight)
|
||||||
|
elif col == "m":
|
||||||
|
monster = Monster((col_index, row_index), self.sprites)
|
||||||
|
self.map[row_index][col_index] = monster
|
||||||
|
self.list_monsters.append(monster)
|
||||||
|
elif col == "c":
|
||||||
|
castle_count += 1
|
||||||
|
if castle_count == 4:
|
||||||
|
castle = Castle((col_index, row_index), self.sprites)
|
||||||
|
self.map[row_index][col_index] = castle
|
||||||
|
self.list_castles.append(castle)
|
||||||
|
|
||||||
|
def handle_turn(self):
|
||||||
|
print("next turn")
|
||||||
|
current_knight = self.knights_queue.dequeue_knight()
|
||||||
|
knight_pos_x = current_knight.position[0]
|
||||||
|
knight_pos_y = current_knight.position[1]
|
||||||
|
state = State(knight_pos_y, knight_pos_x, current_knight.direction)
|
||||||
|
|
||||||
|
castle_cords = (self.list_castles[0].position[0], self.list_castles[0].position[1])
|
||||||
|
goal_list = castle_neighbors(self.map, castle_cords[0], castle_cords[1]) # list of castle neighbors
|
||||||
|
action_list = graphsearch(state, self.map, goal_list)
|
||||||
|
print(action_list)
|
||||||
|
|
||||||
|
if len(action_list) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
next_action = action_list.pop(0)
|
||||||
|
if next_action == ACTION.get("rotate_left"):
|
||||||
|
current_knight.rotate_left()
|
||||||
|
elif next_action == ACTION.get("rotate_right"):
|
||||||
|
current_knight.rotate_right()
|
||||||
|
elif next_action == ACTION.get("go"):
|
||||||
|
current_knight.step_forward()
|
||||||
|
self.map[knight_pos_y][knight_pos_x] = ' '
|
||||||
|
|
||||||
|
# update knight on map
|
||||||
|
if current_knight.direction.name == 'UP':
|
||||||
|
self.map[knight_pos_y - 1][knight_pos_x] = current_knight
|
||||||
|
elif current_knight.direction.name == 'RIGHT':
|
||||||
|
self.map[knight_pos_y][knight_pos_x + 1] = current_knight
|
||||||
|
elif current_knight.direction.name == 'DOWN':
|
||||||
|
self.map[knight_pos_y + 1][knight_pos_x] = current_knight
|
||||||
|
elif current_knight.direction.name == 'LEFT':
|
||||||
|
self.map[knight_pos_y][knight_pos_x - 1] = current_knight
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
bg_width = (GRID_CELL_PADDING + GRID_CELL_SIZE) * COLUMNS + BORDER_WIDTH
|
||||||
|
bg_height = (GRID_CELL_PADDING + GRID_CELL_SIZE) * ROWS + BORDER_WIDTH
|
||||||
|
pygame.draw.rect(self.screen, (255, 255, 255), pygame.Rect(5, 5, bg_width, bg_height), 0, BORDER_RADIUS)
|
||||||
|
|
||||||
|
# update and draw the game
|
||||||
|
self.sprites.draw(self.screen)
|
@ -1,36 +1,33 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from common.constants import GRID_CELL_PADDING, GRID_CELL_WIDTH, GRID_CELL_HEIGHT
|
from common.constants import COLUMNS, ROWS
|
||||||
|
|
||||||
|
|
||||||
class Spawner:
|
class Spawner:
|
||||||
def __init__(self, grid, objs_to_spawn_list: list, spawn_area_width=0, spawn_area_height=0, spawn_area_pos_row=0,
|
def __init__(self, map):
|
||||||
spawn_area_pos_column=0, spawn_where_possible=False): # kolumny i wiersze liczymy od 0;
|
self.map = map
|
||||||
self.objs_to_spawn_list = objs_to_spawn_list
|
|
||||||
self.spawn_area_width = spawn_area_width
|
|
||||||
self.spawn_area_height = spawn_area_height
|
|
||||||
self.spawn_area_pos_row = spawn_area_pos_row
|
|
||||||
self.spawn_area_pos_column = spawn_area_pos_column
|
|
||||||
self.grid = grid
|
|
||||||
self.spawn_where_possible = spawn_where_possible
|
|
||||||
|
|
||||||
def spawn(self):
|
def __is_free_field(self, field):
|
||||||
if self.spawn_where_possible:
|
return field == ' '
|
||||||
possible_fields = self.grid.free_fields
|
|
||||||
else:
|
|
||||||
possible_fields = []
|
|
||||||
for field in self.grid.free_fields:
|
|
||||||
if (self.spawn_area_pos_column <= field.column < (self.spawn_area_width + self.spawn_area_pos_column)) \
|
|
||||||
and (self.spawn_area_pos_row <= field.row < (self.spawn_area_height + self.spawn_area_pos_row)):
|
|
||||||
possible_fields.append(field)
|
|
||||||
|
|
||||||
for obj in self.objs_to_spawn_list:
|
def spawn_in_area(self, objects: list, spawn_area_pos_row=0, spawn_area_pos_column=0, spawn_area_width=0,
|
||||||
ran_index = random.randint(0, len(possible_fields)-1)
|
spawn_area_height=0, size=1):
|
||||||
ran_field = possible_fields[ran_index]
|
spawned_objects_count = 0
|
||||||
ran_field.busy = True
|
|
||||||
obj.rect = obj.rect.clamp(ran_field)
|
while spawned_objects_count != len(objects):
|
||||||
self.grid.busy_fields.append(ran_field)
|
x = random.randint(0, spawn_area_height) + spawn_area_pos_row
|
||||||
if ran_field in self.grid.free_fields:
|
y = random.randint(0, spawn_area_width) + spawn_area_pos_column
|
||||||
self.grid.free_fields.remove(ran_field)
|
if x < ROWS-1 and y < COLUMNS-1 and self.__is_free_field(self.map[x][y]):
|
||||||
if ran_field in possible_fields:
|
for i in range(size):
|
||||||
possible_fields.remove(ran_field)
|
for j in range(size):
|
||||||
obj.update()
|
self.map[x-i][y-j] = objects[spawned_objects_count]
|
||||||
|
spawned_objects_count += 1
|
||||||
|
|
||||||
|
def spawn_where_possible(self, objects: list):
|
||||||
|
spawned_objects_count = 0
|
||||||
|
while spawned_objects_count != len(objects):
|
||||||
|
x = random.randint(0, ROWS-1)
|
||||||
|
y = random.randint(0, COLUMNS-1)
|
||||||
|
if self.__is_free_field(self.map[x][y]):
|
||||||
|
self.map[x][y] = objects[spawned_objects_count]
|
||||||
|
spawned_objects_count += 1
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import pygame.image
|
import pygame.image
|
||||||
|
|
||||||
|
from common.helpers import parse_cord
|
||||||
|
|
||||||
|
|
||||||
class Castle(pygame.sprite.Sprite):
|
class Castle(pygame.sprite.Sprite):
|
||||||
images = []
|
def __init__(self, position, group):
|
||||||
|
super().__init__(group)
|
||||||
def __init__(self):
|
self.image = pygame.image.load("./resources/textures/castle.png").convert_alpha()
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
self.image = pygame.image.load("./resources/textures/castle.png")
|
|
||||||
self.image = pygame.transform.scale(self.image, (78, 78))
|
self.image = pygame.transform.scale(self.image, (78, 78))
|
||||||
self.images.append(self.image)
|
self.position = position
|
||||||
self.rect = self.image.get_rect()
|
position_in_px = (parse_cord(position[0]), parse_cord(position[1]))
|
||||||
castle_list = pygame.sprite.Group()
|
self.rect = self.image.get_rect(center=position_in_px)
|
||||||
self.health = 80
|
self.health = 80
|
||||||
|
@ -1,17 +1,58 @@
|
|||||||
import pygame.image
|
import pygame.image
|
||||||
import random
|
import random
|
||||||
|
|
||||||
class Knight(pygame.sprite.Sprite):
|
from common.constants import GRID_CELL_SIZE, Direction
|
||||||
def __init__(self, img):
|
from common.helpers import parse_cord
|
||||||
super().__init__()
|
|
||||||
self.images = []
|
|
||||||
self.image = pygame.image.load("./resources/textures/knight.png")
|
|
||||||
self.image = pygame.transform.scale(self.image, (40, 40))
|
|
||||||
self.images.append(self.image)
|
|
||||||
self.rect = self.image.get_rect()
|
|
||||||
|
|
||||||
|
|
||||||
|
def load_knight_textures():
|
||||||
|
random_index = random.randint(1, 4)
|
||||||
|
states = [
|
||||||
|
pygame.image.load(f'resources/textures/knight_{random_index}_up.png').convert_alpha(), # up = 0
|
||||||
|
pygame.image.load(f'resources/textures/knight_{random_index}_right.png').convert_alpha(), # right = 1
|
||||||
|
pygame.image.load(f'resources/textures/knight_{random_index}_down.png').convert_alpha(), # down = 2
|
||||||
|
pygame.image.load(f'resources/textures/knight_{random_index}_left.png').convert_alpha(), # left = 3
|
||||||
|
]
|
||||||
|
return states
|
||||||
|
|
||||||
|
|
||||||
|
class Knight(pygame.sprite.Sprite):
|
||||||
|
|
||||||
|
def __init__(self, position, group, team):
|
||||||
|
super().__init__(group)
|
||||||
|
|
||||||
|
self.direction = Direction.DOWN
|
||||||
|
self.states = load_knight_textures()
|
||||||
|
|
||||||
|
self.image = self.states[self.direction.value]
|
||||||
|
self.position = position
|
||||||
|
position_in_px = (parse_cord(position[0]), parse_cord(position[1]))
|
||||||
|
self.rect = self.image.get_rect(topleft=position_in_px)
|
||||||
|
|
||||||
|
self.team = team
|
||||||
self.health = random.randint(7, 12)
|
self.health = random.randint(7, 12)
|
||||||
self.attack = random.randint(4, 7)
|
self.attack = random.randint(4, 7)
|
||||||
self.defense = random.randint(1,4)
|
self.defense = random.randint(1, 4)
|
||||||
self.points = 1
|
self.points = 1
|
||||||
|
|
||||||
|
def rotate_left(self):
|
||||||
|
self.direction = self.direction.left()
|
||||||
|
self.image = self.states[self.direction.value]
|
||||||
|
|
||||||
|
def rotate_right(self):
|
||||||
|
self.direction = self.direction.right()
|
||||||
|
self.image = self.states[self.direction.value]
|
||||||
|
|
||||||
|
def step_forward(self):
|
||||||
|
if self.direction.name == 'UP':
|
||||||
|
self.position = (self.position[0], self.position[1] - 1)
|
||||||
|
self.rect.y = self.rect.y - GRID_CELL_SIZE - 5
|
||||||
|
elif self.direction.name == 'RIGHT':
|
||||||
|
self.position = (self.position[0] + 1, self.position[1])
|
||||||
|
self.rect.x = self.rect.x + GRID_CELL_SIZE + 5
|
||||||
|
elif self.direction.name == 'DOWN':
|
||||||
|
self.position = (self.position[0], self.position[1] + 1)
|
||||||
|
self.rect.y = self.rect.y + GRID_CELL_SIZE + 5
|
||||||
|
elif self.direction.name == 'LEFT':
|
||||||
|
self.position = (self.position[0] - 1, self.position[1])
|
||||||
|
self.rect.x = self.rect.x - GRID_CELL_SIZE - 5
|
||||||
|
@ -1,47 +1,39 @@
|
|||||||
import pygame.image
|
import pygame.image
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
from common.helpers import parse_cord
|
||||||
|
|
||||||
|
monster_images = [
|
||||||
|
pygame.image.load("./resources/textures/dragon2.png"),
|
||||||
|
pygame.image.load("./resources/textures/birb.png"),
|
||||||
|
pygame.image.load("./resources/textures/wolfart.png"),
|
||||||
|
pygame.image.load("./resources/textures/goblin.png"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class Monster(pygame.sprite.Sprite):
|
class Monster(pygame.sprite.Sprite):
|
||||||
monster_images = []
|
def __init__(self, position, group):
|
||||||
|
super().__init__(group)
|
||||||
def __init__(self):
|
self.image = random.choice(monster_images)
|
||||||
super().__init__()
|
self.image = pygame.transform.scale(self.image, (40, 40))
|
||||||
|
position_in_px = (parse_cord(position[0]), parse_cord(position[1]))
|
||||||
self.monster_image1 = pygame.image.load("./resources/textures/dragon2.png")
|
self.rect = self.image.get_rect(topleft=position_in_px)
|
||||||
self.monster_image1 = pygame.transform.scale(self.monster_image1, (40, 40))
|
|
||||||
self.monster_image2 = pygame.image.load("./resources/textures/birb.png")
|
|
||||||
self.monster_image2 = pygame.transform.scale(self.monster_image2, (40, 40))
|
|
||||||
self.monster_image3 = pygame.image.load("./resources/textures/wolfart.png")
|
|
||||||
self.monster_image3 = pygame.transform.scale(self.monster_image3, (40, 40))
|
|
||||||
self.monster_image4 = pygame.image.load("./resources/textures/goblin.png")
|
|
||||||
self.monster_image4 = pygame.transform.scale(self.monster_image4, (40, 40))
|
|
||||||
self.monster_images.append(self.monster_image1)
|
|
||||||
self.monster_images.append(self.monster_image2)
|
|
||||||
self.monster_images.append(self.monster_image3)
|
|
||||||
self.monster_images.append(self.monster_image4)
|
|
||||||
#self.images.append(self.image1)
|
|
||||||
self.image = random.choice(self.monster_images)
|
|
||||||
self.rect = self.image.get_rect()
|
|
||||||
monster_list = pygame.sprite.Group()
|
|
||||||
|
|
||||||
|
|
||||||
self.health = random.randrange(15, 25)
|
self.health = random.randrange(15, 25)
|
||||||
self.attack = random.randrange(2, 10)
|
self.attack = random.randrange(2, 10)
|
||||||
if self.image == self.monster_images[0]:
|
if self.image == monster_images[0]:
|
||||||
self.health = 20
|
self.health = 20
|
||||||
self.attack = 9
|
self.attack = 9
|
||||||
self.points = 10
|
self.points = 10
|
||||||
elif self.image == self.monster_images[1]:
|
elif self.image == monster_images[1]:
|
||||||
self.health = 15
|
self.health = 15
|
||||||
self.attack = 7
|
self.attack = 7
|
||||||
self.points = 7
|
self.points = 7
|
||||||
elif self.image == self.monster_images[2]:
|
elif self.image == monster_images[2]:
|
||||||
self.health = 10
|
self.health = 10
|
||||||
self.attack = 4
|
self.attack = 4
|
||||||
self.points = 4
|
self.points = 4
|
||||||
elif self.image == self.monster_images[3]:
|
elif self.image == monster_images[3]:
|
||||||
self.health = 7
|
self.health = 7
|
||||||
self.attack = 2
|
self.attack = 2
|
||||||
self.points = 2
|
self.points = 2
|
||||||
|
|
||||||
|
12
models/tile.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import pygame
|
||||||
|
|
||||||
|
from common.helpers import parse_cord
|
||||||
|
|
||||||
|
|
||||||
|
class Tile(pygame.sprite.Sprite):
|
||||||
|
def __init__(self, position, image, group, tile_type=' '):
|
||||||
|
super().__init__(group)
|
||||||
|
self.image = image
|
||||||
|
position_in_px = (parse_cord(position[0]), parse_cord(position[1]))
|
||||||
|
self.rect = self.image.get_rect(topleft=position_in_px)
|
||||||
|
self.tile_type = tile_type
|
BIN
resources/textures/knight_1_down.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
resources/textures/knight_1_left.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
resources/textures/knight_1_right.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
resources/textures/knight_1_up.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
resources/textures/knight_2_down.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
resources/textures/knight_2_left.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
resources/textures/knight_2_right.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
resources/textures/knight_2_up.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
resources/textures/knight_3_down.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
resources/textures/knight_3_left.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
resources/textures/knight_3_right.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
resources/textures/knight_3_up.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
resources/textures/knight_4_down.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
resources/textures/knight_4_left.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
resources/textures/knight_4_right.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
resources/textures/knight_4_up.png
Normal file
After Width: | Height: | Size: 15 KiB |
@ -1,7 +1,7 @@
|
|||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
from common.colors import FONT_DARK, ORANGE, WHITE
|
from common.colors import FONT_DARK, ORANGE, WHITE
|
||||||
from common.constants import COLUMNS, GRID_CELL_PADDING, GRID_CELL_WIDTH, BORDER_WIDTH, BORDER_RADIUS
|
from common.constants import COLUMNS, GRID_CELL_PADDING, GRID_CELL_SIZE, BORDER_WIDTH, BORDER_RADIUS
|
||||||
from common.helpers import draw_text
|
from common.helpers import draw_text
|
||||||
|
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ class Logs:
|
|||||||
self.grid = []
|
self.grid = []
|
||||||
|
|
||||||
def draw(self, screen):
|
def draw(self, screen):
|
||||||
x = (GRID_CELL_PADDING + GRID_CELL_WIDTH) * COLUMNS + BORDER_WIDTH + 15
|
x = (GRID_CELL_PADDING + GRID_CELL_SIZE) * COLUMNS + BORDER_WIDTH + 15
|
||||||
y = 470
|
y = 470
|
||||||
|
|
||||||
# background
|
# background
|
||||||
|
66
ui/screens/main_menu.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from common.colors import WHITE, FONT_DARK
|
||||||
|
from common.helpers import draw_text
|
||||||
|
from ui.screens.credits import Credits
|
||||||
|
from ui.screens.options import Options
|
||||||
|
from ui.screens.screen import Screen
|
||||||
|
|
||||||
|
|
||||||
|
class MainMenu(Screen):
|
||||||
|
def __init__(self, screen, clock, bg, btn_play_action, btn_options_action, btn_credits_action):
|
||||||
|
super().__init__('main_menu', screen, clock)
|
||||||
|
self.click = False
|
||||||
|
self.bg = bg
|
||||||
|
self.btn_play_action = btn_play_action
|
||||||
|
self.btn_options_action = btn_options_action
|
||||||
|
self.btn_credits_action = btn_credits_action
|
||||||
|
|
||||||
|
def display_screen(self):
|
||||||
|
running = True
|
||||||
|
while running:
|
||||||
|
self.screen.blit(self.bg, (0, 0))
|
||||||
|
|
||||||
|
pygame.draw.rect(self.screen, (255, 255, 255), pygame.Rect(800, 100, 400, 500), 0, 5)
|
||||||
|
draw_text('MAIN MENU', FONT_DARK, self.screen, 850, 150, 30, True)
|
||||||
|
|
||||||
|
mx, my = pygame.mouse.get_pos()
|
||||||
|
|
||||||
|
button_1 = pygame.Rect(850, 250, 300, 50)
|
||||||
|
button_2 = pygame.Rect(850, 350, 300, 50)
|
||||||
|
button_3 = pygame.Rect(850, 450, 300, 50)
|
||||||
|
if button_1.collidepoint((mx, my)):
|
||||||
|
if self.click:
|
||||||
|
self.btn_play_action()
|
||||||
|
if button_2.collidepoint((mx, my)):
|
||||||
|
if self.click:
|
||||||
|
self.btn_options_action()
|
||||||
|
if button_3.collidepoint((mx, my)):
|
||||||
|
if self.click:
|
||||||
|
self.btn_credits_action()
|
||||||
|
pygame.draw.rect(self.screen, (0, 191, 255), button_1, 0, 4)
|
||||||
|
draw_text('PLAY', WHITE, self.screen, 870, 255)
|
||||||
|
|
||||||
|
pygame.draw.rect(self.screen, (0, 191, 255), button_2, 0, 4)
|
||||||
|
draw_text('OPTIONS', WHITE, self.screen, 870, 355)
|
||||||
|
|
||||||
|
pygame.draw.rect(self.screen, (0, 191, 255), button_3, 0, 4)
|
||||||
|
draw_text('CREDITS', WHITE, self.screen, 870, 455)
|
||||||
|
|
||||||
|
self.click = False
|
||||||
|
for event in pygame.event.get():
|
||||||
|
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.MOUSEBUTTONDOWN:
|
||||||
|
if event.button == 1:
|
||||||
|
self.click = True
|
||||||
|
|
||||||
|
pygame.display.update()
|
||||||
|
self.clock.tick(60)
|
@ -1,7 +1,7 @@
|
|||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
from common.colors import FONT_DARK, ORANGE, WHITE, RED
|
from common.colors import FONT_DARK, ORANGE, WHITE, RED
|
||||||
from common.constants import COLUMNS, GRID_CELL_PADDING, GRID_CELL_WIDTH, BORDER_WIDTH, BORDER_RADIUS
|
from common.constants import COLUMNS, GRID_CELL_PADDING, GRID_CELL_SIZE, BORDER_WIDTH, BORDER_RADIUS
|
||||||
from common.helpers import draw_text
|
from common.helpers import draw_text
|
||||||
|
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ class Stats:
|
|||||||
self.grid = []
|
self.grid = []
|
||||||
|
|
||||||
def draw(self, screen):
|
def draw(self, screen):
|
||||||
x = (GRID_CELL_PADDING + GRID_CELL_WIDTH) * COLUMNS + BORDER_WIDTH + 15
|
x = (GRID_CELL_PADDING + GRID_CELL_SIZE) * COLUMNS + BORDER_WIDTH + 15
|
||||||
y = 5
|
y = 5
|
||||||
|
|
||||||
# background
|
# background
|
||||||
|