added cat and plants
This commit is contained in:
parent
5b85d415e4
commit
a0fe606c23
28
domain/entities/cat.py
Normal file
28
domain/entities/cat.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import pygame
|
||||||
|
|
||||||
|
from domain.entities.entity import Entity
|
||||||
|
from domain.world import World
|
||||||
|
|
||||||
|
|
||||||
|
class Cat(Entity):
|
||||||
|
def __init__(self, x: int, y: int, world: World):
|
||||||
|
super().__init__(x, y, "CAT")
|
||||||
|
self.world = world
|
||||||
|
self.last_tick = pygame.time.get_ticks()
|
||||||
|
self.cooldown = 1000
|
||||||
|
self.velocity = 1
|
||||||
|
self.busy = False
|
||||||
|
self.direction = 0
|
||||||
|
|
||||||
|
def move(self, dx: int, dy: int):
|
||||||
|
end_x = self.x + dx
|
||||||
|
end_y = self.y + dy
|
||||||
|
|
||||||
|
if end_x > self.world.width - 1 or end_y > self.world.height - 1 or end_x < 0 or end_y < 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.world.obstacles[self.x][self.y].remove(self)
|
||||||
|
self.x = end_x
|
||||||
|
self.y = end_y
|
||||||
|
self.world.obstacles[end_x][end_y].append(self)
|
||||||
|
|
23
domain/entities/vacuum.py
Normal file
23
domain/entities/vacuum.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from domain.entities.entity import Entity
|
||||||
|
from domain.world import World
|
||||||
|
|
||||||
|
|
||||||
|
class Vacuum(Entity):
|
||||||
|
def __init__(self, x: int, y: int, world: World):
|
||||||
|
super().__init__(x, y, 'VACUUM')
|
||||||
|
self.world = world
|
||||||
|
self.battery = 100
|
||||||
|
# TODO add more properties
|
||||||
|
|
||||||
|
def move(self, dx, dy):
|
||||||
|
end_x = self.x + dx
|
||||||
|
end_y = self.y + dy
|
||||||
|
|
||||||
|
if end_x > self.world.width - 1 or end_y > self.world.height - 1 or end_x < 0 or end_y < 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.world.is_obstacle_at(end_x, end_y):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.x = end_x
|
||||||
|
self.y = end_y
|
@ -1,8 +0,0 @@
|
|||||||
from domain.entity import Entity
|
|
||||||
|
|
||||||
|
|
||||||
class Vacuum(Entity):
|
|
||||||
def __init__(self, x: int, y: int):
|
|
||||||
super().__init__(x, y, 'VACUUM')
|
|
||||||
self.battery = 100
|
|
||||||
# TODO add more properties
|
|
@ -1,19 +1,44 @@
|
|||||||
from domain.entity import Entity
|
from domain.entities.entity import Entity
|
||||||
from domain.vacuum import Vacuum
|
|
||||||
|
|
||||||
|
|
||||||
class World:
|
class World:
|
||||||
def __init__(self, width: int, height: int):
|
def __init__(self, width: int, height: int):
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
self.grid = [
|
self.dust = [
|
||||||
|
[[] for j in range(height)] for i in range(width)
|
||||||
|
]
|
||||||
|
self.obstacles = [
|
||||||
[[] for j in range(height)] for i in range(width)
|
[[] for j in range(height)] for i in range(width)
|
||||||
]
|
]
|
||||||
self.entities = []
|
self.entities = []
|
||||||
|
|
||||||
self.cleaner = Vacuum(0, 0)
|
self.vacuum = None
|
||||||
self.add(self.cleaner)
|
self.cat = None
|
||||||
|
|
||||||
def add(self, entity: Entity):
|
# move: update position from (start_x, start_y) to (end_x, end_y)
|
||||||
self.entities.append(entity)
|
# def move(self, entity: Entity, end_x: int, end_y: int):
|
||||||
self.grid[entity.x][entity.y].append(entity)
|
# # no change
|
||||||
|
# if entity.x == end_x and entity.y == end_y:
|
||||||
|
# return
|
||||||
|
#
|
||||||
|
# # check if object moves beyond border
|
||||||
|
# if end_x > self.width - 1 or end_y > self.height - 1 or end_x < 0 or end_y < 0:
|
||||||
|
# print("Cannot move object beyond board")
|
||||||
|
# return
|
||||||
|
#
|
||||||
|
# # check if destination is empty
|
||||||
|
# # if self.is_obstacle_at(end_x, end_y):
|
||||||
|
# # print(
|
||||||
|
# # f"Cannot move object to ({end_x}, {end_y}): position already occupied"
|
||||||
|
# # )
|
||||||
|
# # return
|
||||||
|
#
|
||||||
|
# # change position in array
|
||||||
|
# self.grid[entity.x][entity.y].remove(entity)
|
||||||
|
# self.grid[end_x][end_y].append(entity)
|
||||||
|
# entity.x = end_x
|
||||||
|
# entity.y = end_y
|
||||||
|
|
||||||
|
def is_obstacle_at(self, x: int, y: int) -> bool:
|
||||||
|
return bool(self.obstacles[x][y])
|
||||||
|
99
main.py
99
main.py
@ -1,3 +1,98 @@
|
|||||||
from Interface.vacuum_render import initial_draw
|
from random import randint
|
||||||
|
|
||||||
initial_draw(500, 10)
|
import pygame
|
||||||
|
|
||||||
|
from Interface.vacuum_render import initial_draw
|
||||||
|
from domain.entities.cat import Cat
|
||||||
|
from domain.entities.entity import Entity
|
||||||
|
from domain.entities.vacuum import Vacuum
|
||||||
|
from domain.world import World
|
||||||
|
from view.renderer import Renderer
|
||||||
|
|
||||||
|
|
||||||
|
# initial_draw(500, 10)
|
||||||
|
|
||||||
|
class Main:
|
||||||
|
def __init__(self):
|
||||||
|
tiles_x = 10
|
||||||
|
tiles_y = 10
|
||||||
|
|
||||||
|
self.renderer = Renderer(800, 800, tiles_x, tiles_y)
|
||||||
|
|
||||||
|
self.world = World(tiles_x, tiles_y)
|
||||||
|
for _ in range(10):
|
||||||
|
temp_x = randint(0, tiles_x - 1)
|
||||||
|
temp_y = randint(0, tiles_y - 1)
|
||||||
|
self.world.dust[temp_x][temp_y].append(Entity(temp_x, temp_y, "PEEL"))
|
||||||
|
self.world.vacuum = Vacuum(1, 1, self.world)
|
||||||
|
self.world.cat = Cat(7, 8, self.world)
|
||||||
|
self.world.obstacles[7][8].append(self.world.cat)
|
||||||
|
self.world.obstacles[2][8].append(Entity(2, 8, "PLANT1"))
|
||||||
|
self.world.obstacles[4][1].append(Entity(4, 1, "PLANT1"))
|
||||||
|
self.world.obstacles[3][4].append(Entity(3, 4, "PLANT2"))
|
||||||
|
self.world.obstacles[8][8].append(Entity(8, 8, "PLANT2"))
|
||||||
|
self.world.obstacles[9][3].append(Entity(9, 3, "PLANT3"))
|
||||||
|
|
||||||
|
self.clock = pygame.time.Clock()
|
||||||
|
self.running = True
|
||||||
|
self.fps = 60
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.running:
|
||||||
|
self.process_input()
|
||||||
|
self.update()
|
||||||
|
self.renderer.render(self.world)
|
||||||
|
self.clock.tick(self.fps)
|
||||||
|
|
||||||
|
pygame.quit()
|
||||||
|
|
||||||
|
def process_input(self):
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
self.running = False
|
||||||
|
if event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == pygame.K_LEFT:
|
||||||
|
self.world.vacuum.move(-1, 0)
|
||||||
|
if event.key == pygame.K_RIGHT:
|
||||||
|
self.world.vacuum.move(1, 0)
|
||||||
|
if event.key == pygame.K_UP:
|
||||||
|
self.world.vacuum.move(0, -1)
|
||||||
|
if event.key == pygame.K_DOWN:
|
||||||
|
self.world.vacuum.move(0, 1)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
now = pygame.time.get_ticks()
|
||||||
|
# region cat random movement
|
||||||
|
cat = self.world.cat
|
||||||
|
if now - cat.last_tick >= cat.cooldown:
|
||||||
|
if not cat.busy:
|
||||||
|
while True:
|
||||||
|
cat.direction = randint(0, 3)
|
||||||
|
if not ((cat.direction == 0 and cat.y == 0)
|
||||||
|
or (cat.direction == 1 and cat.x == self.world.width - 1)
|
||||||
|
or (cat.direction == 2 and cat.y == self.world.height - 1)
|
||||||
|
or (cat.direction == 3 and cat.x == 0)):
|
||||||
|
break
|
||||||
|
|
||||||
|
if cat.direction == 0: # up
|
||||||
|
if cat.busy:
|
||||||
|
cat.move(0, - 1)
|
||||||
|
cat.busy = not cat.busy
|
||||||
|
if cat.direction == 1: # right
|
||||||
|
if cat.busy:
|
||||||
|
cat.move(1, 0)
|
||||||
|
cat.busy = not cat.busy
|
||||||
|
if cat.direction == 2: # down
|
||||||
|
if cat.busy:
|
||||||
|
cat.move(0, 1)
|
||||||
|
cat.busy = not cat.busy
|
||||||
|
if cat.direction == 3: # left
|
||||||
|
if cat.busy:
|
||||||
|
cat.move(-1, 0)
|
||||||
|
cat.busy = not cat.busy
|
||||||
|
cat.last_tick = pygame.time.get_ticks()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = Main()
|
||||||
|
app.run()
|
||||||
|
112
view/renderer.py
Normal file
112
view/renderer.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import random
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
from pygame import Color
|
||||||
|
|
||||||
|
from domain.entities.cat import Cat
|
||||||
|
from domain.world import World, Entity
|
||||||
|
|
||||||
|
|
||||||
|
class Renderer:
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
width=800,
|
||||||
|
height=800,
|
||||||
|
tiles_x=10,
|
||||||
|
tiles_y=10,
|
||||||
|
):
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
|
||||||
|
self.tiles_x = tiles_x
|
||||||
|
self.tiles_y = tiles_y
|
||||||
|
|
||||||
|
self.tile_width = self.width / self.tiles_x
|
||||||
|
self.tile_height = self.height / self.tiles_y
|
||||||
|
|
||||||
|
pygame.init()
|
||||||
|
|
||||||
|
pygame.display.set_caption("AI Vacuum Cleaner")
|
||||||
|
self.screen = pygame.display.set_mode((self.width, self.height))
|
||||||
|
|
||||||
|
self.sprites = {
|
||||||
|
"VACUUM": pygame.transform.scale(pygame.image.load("media/sprites/vacuum.png"),
|
||||||
|
(self.tile_width, self.tile_height)),
|
||||||
|
"WALL": pygame.transform.scale(pygame.image.load("media/sprites/wall.png"),
|
||||||
|
(self.tile_width, self.tile_height)),
|
||||||
|
"TILE": pygame.transform.scale(pygame.image.load("media/sprites/tile_cropped.jpeg"),
|
||||||
|
(self.tile_width, self.tile_height)),
|
||||||
|
"PEEL": pygame.transform.scale(pygame.image.load("media/sprites/peel.webp"),
|
||||||
|
(self.tile_width, self.tile_height)),
|
||||||
|
"CAT_FRONT": pygame.transform.scale(pygame.image.load("Interface/images/cat/standing_front.png"),
|
||||||
|
(self.tile_width, self.tile_height)),
|
||||||
|
"CAT_BACK": pygame.transform.scale(pygame.image.load("Interface/images/cat/standing_back.png"),
|
||||||
|
(self.tile_width, self.tile_height)),
|
||||||
|
"CAT_LEFT": pygame.transform.scale(pygame.image.load("Interface/images/cat/standing_left.png"),
|
||||||
|
(self.tile_width, self.tile_height)),
|
||||||
|
"CAT_RIGHT": pygame.transform.scale(pygame.image.load("Interface/images/cat/standing_right.png"),
|
||||||
|
(self.tile_width, self.tile_height)),
|
||||||
|
"PLANT1": pygame.transform.scale(pygame.image.load("Interface/images/plants/plant1.png"),
|
||||||
|
(self.tile_width + self.tile_width / 4, self.tile_height + self.tile_height / 4)),
|
||||||
|
"PLANT2": pygame.transform.scale(pygame.image.load("Interface/images/plants/plant2.png"),
|
||||||
|
(self.tile_width + self.tile_width / 4, self.tile_height + self.tile_height / 4)),
|
||||||
|
"PLANT3": pygame.transform.scale(pygame.image.load("Interface/images/plants/plant3.png"),
|
||||||
|
(self.tile_width + self.tile_width / 4, self.tile_height + self.tile_height / 4)),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cat_direction_sprite = {
|
||||||
|
0: self.sprites["CAT_BACK"],
|
||||||
|
1: self.sprites["CAT_RIGHT"],
|
||||||
|
2: self.sprites["CAT_FRONT"],
|
||||||
|
3: self.sprites["CAT_LEFT"],
|
||||||
|
}
|
||||||
|
|
||||||
|
def render(self, world: World):
|
||||||
|
self.render_floor()
|
||||||
|
self.render_board()
|
||||||
|
for x in range(world.width):
|
||||||
|
for y in range(world.height):
|
||||||
|
for entity in world.dust[x][y]:
|
||||||
|
self.draw_entity(entity)
|
||||||
|
for x in range(world.width):
|
||||||
|
for y in range(world.height):
|
||||||
|
for entity in world.obstacles[x][y]:
|
||||||
|
self.draw_entity(entity)
|
||||||
|
self.draw_entity(world.vacuum)
|
||||||
|
self.draw_entity(world.cat)
|
||||||
|
pygame.display.update()
|
||||||
|
|
||||||
|
def line(self, x_1, y_1, x_2, y_2, color=None):
|
||||||
|
pygame.draw.line(self.screen, color, (x_1, y_1), (x_2, y_2))
|
||||||
|
|
||||||
|
def render_board(self, color=Color("black")):
|
||||||
|
for i in range(1, self.tiles_x):
|
||||||
|
self.line(self.tile_width * i, 0, self.tile_width * i, self.height, color=color)
|
||||||
|
|
||||||
|
for i in range(1, self.tiles_y):
|
||||||
|
self.line(0, self.tile_height * i, self.width, self.tile_height * i, color=color)
|
||||||
|
|
||||||
|
def draw_entity(self, entity: Entity):
|
||||||
|
sprite = self.sprites.get(entity.type, None)
|
||||||
|
draw_pos = (entity.x * self.tile_width, entity.y * self.tile_height)
|
||||||
|
if "PLANT" in entity.type:
|
||||||
|
draw_pos = ((entity.x - 0.1) * self.tile_width, (entity.y - 0.25) * self.tile_height)
|
||||||
|
if "CAT" in entity.type and isinstance(entity, Cat):
|
||||||
|
sprite = self.cat_direction_sprite[entity.direction]
|
||||||
|
self.screen.blit(sprite, draw_pos)
|
||||||
|
|
||||||
|
def draw_sprite(self, x: int, y: int, sprite_name: str):
|
||||||
|
self.screen.blit(
|
||||||
|
self.sprites[sprite_name],
|
||||||
|
(x * self.tile_width, y * self.tile_height)
|
||||||
|
)
|
||||||
|
|
||||||
|
def fill_grid_with_sprite(self, sprite):
|
||||||
|
for tile_x in range(self.tiles_x):
|
||||||
|
for tile_y in range(self.tiles_y):
|
||||||
|
self.draw_sprite(tile_x, tile_y, sprite)
|
||||||
|
|
||||||
|
def render_floor(self):
|
||||||
|
self.fill_grid_with_sprite("TILE")
|
@ -1,112 +0,0 @@
|
|||||||
from random import randint
|
|
||||||
|
|
||||||
import pygame
|
|
||||||
from pygame import Color
|
|
||||||
|
|
||||||
from domain.world import World, Entity
|
|
||||||
|
|
||||||
|
|
||||||
class UserInterface:
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
width=800,
|
|
||||||
height=800,
|
|
||||||
tiles_x=10,
|
|
||||||
tiles_y=10,
|
|
||||||
):
|
|
||||||
self.width = width
|
|
||||||
self.height = height
|
|
||||||
|
|
||||||
self.tiles_x = tiles_x
|
|
||||||
self.tiles_y = tiles_y
|
|
||||||
|
|
||||||
self.tile_width = self.width / self.tiles_x
|
|
||||||
self.tile_height = self.height / self.tiles_y
|
|
||||||
|
|
||||||
self.world = World(tiles_x, tiles_y)
|
|
||||||
for _ in range(10):
|
|
||||||
temp_x = randint(0, tiles_x - 1)
|
|
||||||
temp_y = randint(0, tiles_y - 1)
|
|
||||||
self.world.add(Entity(temp_x, temp_y, 'PEEL'))
|
|
||||||
|
|
||||||
pygame.init()
|
|
||||||
|
|
||||||
pygame.display.set_caption('AI Vacuum Cleaner')
|
|
||||||
self.screen = pygame.display.set_mode((self.width, self.height))
|
|
||||||
|
|
||||||
self.sprites = {
|
|
||||||
'VACUUM': pygame.transform.scale(pygame.image.load('../media/sprites/vacuum.png'),
|
|
||||||
(self.tile_width, self.tile_height)),
|
|
||||||
'WALL': pygame.transform.scale(pygame.image.load('../media/sprites/wall.png'),
|
|
||||||
(self.tile_width, self.tile_height)),
|
|
||||||
'TILE': pygame.transform.scale(pygame.image.load('../media/sprites/tile_cropped.jpeg'),
|
|
||||||
(self.tile_width, self.tile_height)),
|
|
||||||
'PEEL': pygame.transform.scale(pygame.image.load('../media/sprites/peel.webp'),
|
|
||||||
(self.tile_width, self.tile_height)),
|
|
||||||
}
|
|
||||||
|
|
||||||
self.clock = pygame.time.Clock()
|
|
||||||
self.running = True
|
|
||||||
self.fps = 60
|
|
||||||
|
|
||||||
def process_input(self):
|
|
||||||
for event in pygame.event.get():
|
|
||||||
if event.type == pygame.QUIT:
|
|
||||||
self.running = False
|
|
||||||
if event.type == pygame.KEYDOWN:
|
|
||||||
if event.key == pygame.K_LEFT and self.world.cleaner.x > 0:
|
|
||||||
self.world.cleaner.x -= 1
|
|
||||||
if event.key == pygame.K_RIGHT and self.world.cleaner.x < self.tiles_x - 1:
|
|
||||||
self.world.cleaner.x += 1
|
|
||||||
if event.key == pygame.K_UP and self.world.cleaner.y > 0:
|
|
||||||
self.world.cleaner.y -= 1
|
|
||||||
if event.key == pygame.K_DOWN and self.world.cleaner.y < self.tiles_y - 1:
|
|
||||||
self.world.cleaner.y += 1
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def render(self):
|
|
||||||
self.render_floor()
|
|
||||||
self.render_board()
|
|
||||||
for entity in self.world.entities:
|
|
||||||
self.draw_sprite(entity.x, entity.y, entity.type)
|
|
||||||
self.draw_sprite(self.world.cleaner.x, self.world.cleaner.y, self.world.cleaner.type)
|
|
||||||
pygame.display.update()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
while self.running:
|
|
||||||
self.process_input()
|
|
||||||
self.update()
|
|
||||||
self.render()
|
|
||||||
self.clock.tick(self.fps)
|
|
||||||
|
|
||||||
pygame.quit()
|
|
||||||
|
|
||||||
def line(self, x_1, y_1, x_2, y_2, color=None):
|
|
||||||
pygame.draw.line(self.screen, color, (x_1, y_1), (x_2, y_2))
|
|
||||||
|
|
||||||
def render_board(self, color=Color('black')):
|
|
||||||
for i in range(1, self.tiles_x):
|
|
||||||
self.line(self.tile_width * i, 0, self.tile_width * i, self.height, color=color)
|
|
||||||
|
|
||||||
for i in range(1, self.tiles_y):
|
|
||||||
self.line(0, self.tile_height * i, self.width, self.tile_height * i, color=color)
|
|
||||||
|
|
||||||
def draw_sprite(self, x, y, sprite):
|
|
||||||
self.screen.blit(
|
|
||||||
self.sprites[sprite],
|
|
||||||
(x * self.tile_width, y * self.tile_height)
|
|
||||||
)
|
|
||||||
|
|
||||||
def fill_grid_with_sprite(self, sprite):
|
|
||||||
for tile_x in range(self.tiles_x):
|
|
||||||
for tile_y in range(self.tiles_y):
|
|
||||||
self.draw_sprite(tile_x, tile_y, sprite)
|
|
||||||
|
|
||||||
def render_floor(self):
|
|
||||||
self.fill_grid_with_sprite('TILE')
|
|
||||||
|
|
||||||
|
|
||||||
UserInterface(800, 800, 10, 10).run()
|
|
Loading…
Reference in New Issue
Block a user