diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..4607abd
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/../../../:\ai-project\.idea/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/ai-project.iml b/.idea/ai-project.iml
new file mode 100644
index 0000000..d0876a7
--- /dev/null
+++ b/.idea/ai-project.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..d1e22ec
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..57157c8
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/apple.png b/assets/apple.png
new file mode 100644
index 0000000..609435b
Binary files /dev/null and b/assets/apple.png differ
diff --git a/assets/map1.png b/assets/map1.png
new file mode 100644
index 0000000..21920bf
Binary files /dev/null and b/assets/map1.png differ
diff --git a/assets/map2.png b/assets/map2.png
new file mode 100644
index 0000000..90e2f7e
Binary files /dev/null and b/assets/map2.png differ
diff --git a/assets/map3.png b/assets/map3.png
new file mode 100644
index 0000000..11cf3ae
Binary files /dev/null and b/assets/map3.png differ
diff --git a/assets/map4.png b/assets/map4.png
new file mode 100644
index 0000000..1d49162
Binary files /dev/null and b/assets/map4.png differ
diff --git a/assets/player.png b/assets/player.png
new file mode 100644
index 0000000..3aebbc3
Binary files /dev/null and b/assets/player.png differ
diff --git a/assets/stone.png b/assets/stone.png
new file mode 100644
index 0000000..a3638f6
Binary files /dev/null and b/assets/stone.png differ
diff --git a/assets/tree.png b/assets/tree.png
new file mode 100644
index 0000000..78004b9
Binary files /dev/null and b/assets/tree.png differ
diff --git a/assets/water.png b/assets/water.png
new file mode 100644
index 0000000..d08257a
Binary files /dev/null and b/assets/water.png differ
diff --git a/assets/wood.png b/assets/wood.png
new file mode 100644
index 0000000..993aee0
Binary files /dev/null and b/assets/wood.png differ
diff --git a/survival/__init__.py b/survival/__init__.py
new file mode 100644
index 0000000..0f7bd0d
--- /dev/null
+++ b/survival/__init__.py
@@ -0,0 +1,44 @@
+import pygame
+
+from game.game_map import GameMap
+
+window_width = 1280
+window_height = 720
+
+
+def draw_game():
+ game_map.draw(win)
+ pygame.display.update()
+
+
+def update_game(pressed_keys):
+ game_map.update(pressed_keys)
+ pass
+
+
+if __name__ == '__main__':
+ pygame.init()
+
+ win = pygame.display.set_mode((window_width, window_height))
+ pygame.display.set_caption("AI Project")
+
+ clock = pygame.time.Clock()
+
+ game_map = GameMap(int(window_width/32), int(window_height/32) + 1)
+
+ run = True
+
+ while run:
+ # Set the framerate
+ clock.tick(60)
+
+ events = pygame.event.get()
+
+ for event in events:
+ if event.type == pygame.QUIT:
+ run = False
+
+ keys = pygame.key.get_pressed()
+
+ draw_game()
+ update_game(keys)
diff --git a/survival/camera.py b/survival/camera.py
new file mode 100644
index 0000000..91f4129
--- /dev/null
+++ b/survival/camera.py
@@ -0,0 +1,16 @@
+from pygame.rect import Rect
+
+
+class Camera:
+ def __init__(self, width, height):
+ self.camera = Rect(0, 0, width, height)
+ self.width = width
+ self.height = height
+
+ def apply(self, game_object):
+ return game_object.get_rect().move(self.camera.topleft)
+
+ def update(self, target_object):
+ x = -target_object.get_rect().x + int(self.width / 2)
+ y = -target_object.get_rect().y + int(self.height / 2)
+ self.camera = Rect(x, y, self.width, self.height)
diff --git a/survival/game_map.py b/survival/game_map.py
new file mode 100644
index 0000000..bea79ad
--- /dev/null
+++ b/survival/game_map.py
@@ -0,0 +1,50 @@
+import os
+
+import pygame
+from pygame.rect import Rect
+
+from game.player import Player
+from game.quad_tree import QuadTree
+from game.stone import Stone
+from game.tile import Tile
+
+
+class GameMap:
+
+ def __init__(self, width, height):
+ self.width = width
+ self.height = height
+ self.game_objects = []
+ self.player = Player()
+ self.game_objects.append(self.player)
+ self.tiles = [[Tile() for x in range(width)] for y in range(height)]
+ self.textures = [pygame.image.load(os.path.join('..', 'assets', 'map1.png')),
+ pygame.image.load(os.path.join('..', 'assets', 'map2.png')),
+ pygame.image.load(os.path.join('..', 'assets', 'map3.png')),
+ pygame.image.load(os.path.join('..', 'assets', 'map4.png'))]
+ self.game_objects.append(Stone([100, 200]))
+ self.quad_tree = QuadTree(0, Rect(0, 0, width * 32, height * 32))
+
+ def draw(self, window):
+ for y in range(self.height):
+ for x in range(self.width):
+ window.blit(self.textures[self.tiles[y][x].background_id], (x * 32, y * 32))
+
+ for game_object in self.game_objects:
+ game_object.draw(window)
+
+ def update(self, pressed_keys):
+ self.quad_tree.clear()
+
+ for game_object in self.game_objects:
+ self.quad_tree.insert(game_object)
+
+ self.player.update(pressed_keys)
+
+ for game_object in self.game_objects:
+ possible_colliders = []
+ self.quad_tree.retrieve(possible_colliders, game_object)
+ for collider in possible_colliders:
+ if game_object.get_rect().colliderect(collider.get_rect()) and game_object != collider:
+ game_object.velocity = [0, 0]
+ game_object.pos = game_object.last_pos
diff --git a/survival/game_object.py b/survival/game_object.py
new file mode 100644
index 0000000..dd27093
--- /dev/null
+++ b/survival/game_object.py
@@ -0,0 +1,20 @@
+import pygame
+from pygame.rect import Rect
+
+
+class GameObject:
+
+ def __init__(self, pos, texture):
+ self.pos = pos
+ self.last_pos = pos
+ self.texture = pygame.image.load(texture)
+ self.texture = pygame.transform.scale(self.texture, (64, 64))
+ self.width = self.texture.get_width()
+ self.height = self.texture.get_height()
+ self.velocity = [0, 0]
+
+ def draw(self, window):
+ window.blit(self.texture, self.pos)
+
+ def get_rect(self):
+ return Rect(self.pos[0], self.pos[1], self.width, self.height)
diff --git a/survival/player.py b/survival/player.py
new file mode 100644
index 0000000..116a739
--- /dev/null
+++ b/survival/player.py
@@ -0,0 +1,34 @@
+import os
+
+import pygame
+
+from game.game_object import GameObject
+
+
+class Player(GameObject):
+ def __init__(self):
+ super().__init__([0, 0], os.path.join('..', 'assets', 'player.png'))
+
+ def draw(self, window):
+ super().draw(window)
+
+ def update(self, pressed_keys):
+ if pressed_keys[pygame.K_LEFT]:
+ self.velocity[0] = -1
+ elif pressed_keys[pygame.K_RIGHT]:
+ self.velocity[0] = 1
+ else:
+ self.velocity[0] = 0
+
+ if pressed_keys[pygame.K_DOWN]:
+ self.velocity[1] = 1
+ elif pressed_keys[pygame.K_UP]:
+ self.velocity[1] = -1
+ else:
+ self.velocity[1] = 0
+
+ self.last_pos = [self.pos[0], self.pos[1]]
+
+ self.pos[0] += self.velocity[0]
+ self.pos[1] += self.velocity[1]
+
diff --git a/survival/quad_tree.py b/survival/quad_tree.py
new file mode 100644
index 0000000..44a35ce
--- /dev/null
+++ b/survival/quad_tree.py
@@ -0,0 +1,116 @@
+import pygame
+from pygame.rect import Rect
+
+
+class QuadTree:
+ """
+ How to use:
+
+ 1) Create new quadtree: QuadTree(0, Rect(0, 0, width, height))
+ 2) Every frame clear the quadtree and insert all objects into it.
+ 3) Get the possible colliders for each objects and check if they collide.
+
+ for object in objects:
+ possible_colliders = []
+ possible_colliders = quad_tree.retrieve(possible_colliders, object)
+
+ for collider in possible_colliders:
+ # Check collision here
+
+ """
+ MAX_OBJECTS = 10
+ MAX_LEVELS = 5
+
+ def __init__(self, level, bounds):
+ self.level = level
+ self.bounds = bounds
+ self.objects = []
+ self.nodes = []
+
+ def clear(self):
+ """
+ Clears the quadtree recursively.
+ """
+ self.objects.clear()
+
+ for node in self.nodes:
+ if node is not None:
+ node.clear()
+
+ def split(self):
+ """
+ Splits the node into 4 sub nodes.
+ """
+ sub_width = int(self.bounds.width / 2)
+ sub_height = int(self.bounds.height / 2)
+ x = int(self.bounds.x)
+ y = int(self.bounds.y)
+
+ self.nodes.append(QuadTree(self.level + 1, Rect(x + sub_width, y, sub_width, sub_height)))
+ self.nodes.append(QuadTree(self.level + 1, Rect(x, y, sub_width, sub_height)))
+ self.nodes.append(QuadTree(self.level + 1, Rect(x, y + sub_height, sub_width, sub_height)))
+ self.nodes.append(QuadTree(self.level + 1, Rect(x + sub_width, y + sub_height, sub_width, sub_height)))
+
+ def get_index(self, rect):
+ """
+ Checks which node the object belongs to.
+ """
+ index = -1
+ vertical_point = self.bounds.x + (self.bounds.width / 2)
+ horizontal_point = self.bounds.y + (self.bounds.height / 2)
+
+ top_quadrant = rect.y < horizontal_point and rect.y + rect.height < horizontal_point
+ bot_quadrant = rect.y > horizontal_point
+
+ if rect.x < vertical_point and rect.x + rect.width < vertical_point:
+ if top_quadrant:
+ index = 1
+ elif bot_quadrant:
+ index = 2
+ elif rect.x > vertical_point:
+ if top_quadrant:
+ index = 0
+ elif bot_quadrant:
+ index = 3
+
+ return index
+
+ def insert(self, game_object):
+ """
+ Inserts given game object into the quadtree.
+ If objects count exceeds the limit the node is split and
+ all objects are added to their corresponding nodes.
+ """
+ rect = Rect(game_object.pos[0], game_object.pos[1], game_object.width, game_object.height)
+ if len(self.nodes) > 0:
+ index = self.get_index(rect)
+
+ if index != -1:
+ self.nodes[index].insert(rect)
+ return
+
+ self.objects.append(game_object)
+
+ if len(self.objects) > self.MAX_OBJECTS and self.level < self.MAX_LEVELS:
+ if len(self.nodes) == 0:
+ self.split()
+
+ i = 0
+ while i < len(self.objects):
+ index = self.get_index(self.objects[i])
+ if index == -1:
+ i += 1
+ else:
+ self.nodes[index].insert(self.objects.remove(i))
+
+ def retrieve(self, objects, game_object):
+ """
+ Returns all objects that collide with given rectangle.
+ """
+ rect = game_object.get_rect()
+ index = self.get_index(rect)
+
+ if index != -1 and len(self.nodes) > 0:
+ self.nodes[index].retrieve(objects, rect)
+
+ objects.extend(self.objects)
diff --git a/survival/stone.py b/survival/stone.py
new file mode 100644
index 0000000..66c66bb
--- /dev/null
+++ b/survival/stone.py
@@ -0,0 +1,9 @@
+import os
+
+from game.game_object import GameObject
+
+
+class Stone(GameObject):
+
+ def __init__(self, pos):
+ super().__init__(pos, os.path.join('..', 'assets', 'stone.png'))
diff --git a/survival/tile.py b/survival/tile.py
new file mode 100644
index 0000000..bff4aab
--- /dev/null
+++ b/survival/tile.py
@@ -0,0 +1,7 @@
+import pygame
+from random import randrange
+
+
+class Tile:
+ def __init__(self):
+ self.background_id = randrange(4)