Skip to content
This repository was archived by the owner on Feb 22, 2020. It is now read-only.

Commit 17649a2

Browse files
Merge pull request #5 from LukasZahradnik/Project-basic-core
Implement basic app core
2 parents 6b965d0 + 19d0516 commit 17649a2

File tree

10 files changed

+188
-7
lines changed

10 files changed

+188
-7
lines changed

excellent-exorcists/requirements.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
certifi==2019.11.28
2+
chardet==3.0.4
3+
docutils==0.16
4+
idna==2.8
5+
Kivy==1.11.1
6+
Kivy-Garden==0.1.4
7+
Pygments==2.5.2
8+
requests==2.22.0
9+
urllib3==1.25.7

excellent-exorcists/src/__init__.py

Whitespace-only changes.

excellent-exorcists/src/core/__init__.py

Whitespace-only changes.

excellent-exorcists/src/core/game.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from kivy.app import App
2+
3+
from src.core.game_loop import GameLoop
4+
from src.core.screen_manager import ScreenManager
5+
6+
7+
class Game(App):
8+
def __init__(self, loop: GameLoop, screen_manager: ScreenManager, **kwargs):
9+
super().__init__(**kwargs)
10+
11+
self.loop = loop
12+
self.screen_manager = screen_manager
13+
14+
self.loop.set_callback(self.loop_callback)
15+
16+
def build(self):
17+
return self.screen_manager
18+
19+
def loop_callback(self, delta):
20+
if self.screen_manager.current is not None:
21+
self.screen_manager.current.update(delta)
22+
self.screen_manager.current.render_screen(delta)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from kivy.clock import Clock
2+
3+
4+
class GameLoop:
5+
def __init__(self):
6+
self.loop = None
7+
self.callback_ = lambda _: _
8+
9+
def set_callback(self, callback):
10+
self.callback_ = callback
11+
12+
def callback(self, delta):
13+
self.callback_(delta)
14+
15+
def start(self, fps: int):
16+
self.loop = Clock.schedule_interval(self.callback, 1.0 / float(fps))
17+
18+
def stop(self):
19+
if self.loop is not None:
20+
self.loop.cancel()
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from kivy.graphics.instructions import RenderContext
2+
from kivy.uix.widget import Widget
3+
4+
5+
class Screen(Widget):
6+
def __init__(self, **kwargs):
7+
super().__init__(**kwargs)
8+
9+
self.render_context = RenderContext()
10+
11+
def render(self, delta):
12+
"""Override this method and render graphics"""
13+
14+
def update(self, delta):
15+
"""Override this method for updating state"""
16+
17+
def on_create(self):
18+
"""Called when initialized from screen manager"""
19+
20+
def on_destroy(self):
21+
"""Called when removed from screen manager"""
22+
23+
def on_open(self):
24+
"""Called when the screen is opened"""
25+
26+
def on_close(self):
27+
"""Called when the screen is closed"""
28+
29+
def on_resize(self, width: int, height: int):
30+
"""Called on window resize"""
31+
32+
def clear(self):
33+
self.canvas.clear()
34+
35+
def render_screen(self, delta):
36+
"""Wrapper method for render, should not be overrided"""
37+
with self.canvas:
38+
self.render(delta)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from kivy.uix.widget import Widget
2+
from kivy.core.window import Window
3+
4+
5+
class InvalidGameScreen(Exception):
6+
def __init__(self, *args, **kwargs):
7+
pass
8+
9+
10+
class ScreenManager(Widget):
11+
def __init__(self, **kwargs):
12+
super().__init__(**kwargs)
13+
self.screens = {}
14+
self.current = None
15+
16+
Window.bind(on_resize=self.on_window_resize)
17+
18+
def on_window_resize(self, _, width: int, height: int):
19+
if self.current is not None:
20+
self.current.width = width
21+
self.current.height = height
22+
self.current.on_resize(width, height)
23+
24+
def add_screen(self, screen_class):
25+
if screen_class in self.screens:
26+
raise InvalidGameScreen(f'Game screen already in screen manager {str(screen_class)}')
27+
28+
screen_instance = screen_class()
29+
self.screens[screen_class] = screen_instance
30+
screen_instance.on_create()
31+
32+
def remove_screen(self, screen_class):
33+
if screen_class not in self.screens:
34+
raise InvalidGameScreen(f'Game screen is not registered in screen manager {str(screen_class)}')
35+
36+
instance = self.screens[screen_class]
37+
del self.screens[screen_class]
38+
39+
instance.on_destroy()
40+
41+
def set_current_screen(self, screen_class):
42+
if screen_class not in self.screens:
43+
raise InvalidGameScreen(f'Invalid game screen class {str(screen_class)}')
44+
45+
if self.current is not None:
46+
self.remove_widget(self.current)
47+
self.current.on_close()
48+
49+
self.current = self.screens[screen_class]
50+
self.current.on_open()
51+
self.add_widget(self.current)

excellent-exorcists/src/main.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
from kivy.app import App
1+
from src.core.game import Game
2+
from src.core.game_loop import GameLoop
3+
from src.core.screen_manager import ScreenManager
24

5+
from src.screens.game_screen import GameScreen
36

4-
class GameApp(App):
5-
6-
def build(self):
7-
root = self.root
8-
97
if __name__ == '__main__':
10-
GameApp().run()
8+
loop = GameLoop()
9+
screen_manager = ScreenManager()
10+
screen_manager.add_screen(GameScreen)
11+
screen_manager.set_current_screen(GameScreen)
12+
13+
loop.start(60)
14+
game = Game(loop, screen_manager)
15+
16+
game.run()

excellent-exorcists/src/screens/__init__.py

Whitespace-only changes.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from kivy.graphics.vertex_instructions import Rectangle
2+
from kivy.graphics import Color
3+
from kivy.uix.label import Label
4+
from src.core.screen import Screen
5+
6+
import random
7+
8+
9+
class GameScreen(Screen):
10+
def __init__(self, **kwargs):
11+
super().__init__(**kwargs)
12+
13+
self.fps = 0
14+
self.positions = [(random.randint(0, 600), random.randint(0, 300)) for _ in range(100)]
15+
16+
def on_resize(self, width: int, height: int):
17+
pass
18+
19+
def render(self, delta: float):
20+
self.clear()
21+
Color(1., 1., 0)
22+
23+
for pos in self.positions:
24+
Rectangle(pos=pos, size=(50, 50))
25+
26+
Color(0, 1, 0)
27+
Label(text=f'FPS: {self.fps}')
28+
29+
def update(self, delta: float):
30+
speed = 10
31+
self.fps = round(1 / delta)
32+
33+
for i in range(len(self.positions)):
34+
x, y = self.positions[i]
35+
self.positions[i] = (x + speed * delta, y + speed * delta)

0 commit comments

Comments
 (0)