Skip to content

Commit

Permalink
Major Refactoring! New configuration.py with the factories. Distincti…
Browse files Browse the repository at this point in the history
…on between PlayerUI and PlayerLogic. Got rid off a dependency cycle. Movement of the player is in the Player's Logic, the PlayerUI just grabs the information where to draw of the logical Player class
  • Loading branch information
macskay committed May 7, 2015
1 parent 3713d20 commit b788b23
Show file tree
Hide file tree
Showing 17 changed files with 248 additions and 184 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
language: python
python:
- "3.4"
- "2.7"
sudo: required
install:
- sudo apt-get update -qq
Expand Down
File renamed without changes
Binary file removed assets/player/player.bmp
Binary file not shown.
Binary file added assets/player/player.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(name="tekmate",
version="0.0.1",
description="Tekmate - Stargate-Based RPG",
description="Tekmate - Stargate-Based Point'n'Click",
author="Max",
packages=['tekmate'],
license="GPLv3",
Expand All @@ -18,7 +18,8 @@
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Natural Language :: English",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 2.7",
"Topic :: Games/Entertainment",
"Topic :: Software Development :: Libraries",
],
)
)
1 change: 0 additions & 1 deletion tekmate/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
__author__ = 'max'
4 changes: 3 additions & 1 deletion tekmate/__main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- encoding: utf-8 -*-
from tekmate.game import PyGameInitializer, TekmateFactory

from tekmate.configuration import PyGameInitializer, TekmateFactory


def main():
Expand All @@ -8,5 +9,6 @@ def main():
game = game_factory.create()
game.enter_mainloop()


if __name__ == "__main__":
main()
68 changes: 68 additions & 0 deletions tekmate/configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# -*- encoding: utf-8 -*-
from glob import glob

from os.path import join, splitext
import pygame
from taz.game import Game

from tekmate.scenes import WorldScene


class PyGameInitializer(object):
CAPTION = "Tek'ma'te"

def __init__(self, configuration):
self.configuration = configuration

def initialize(self):
pygame.init()
self.set_up_display()
self.set_up_mouse()
self.load_global_images()

return self.get_update_context(), self.get_render_context()

def set_up_display(self):
pygame.display.set_mode((self.configuration["display_width"], self.configuration["display_height"]))
pygame.display.set_caption(self.CAPTION)

def set_up_mouse(self):
pygame.mouse.set_visible(True)

def load_global_images(self):
images = dict()
base_path = join("assets", "global")
for image_file in glob(join(base_path, "*.png")):
name = splitext(image_file)
surface = pygame.image.load(join(base_path, image_file)).convert()
surface.set_colorkey((0, 128, 128))
images[name[0]] = surface
return images

def get_render_context(self):
render_context = {
"flip": pygame.display.flip,
"display": pygame.display.get_surface(),
"images-global": self.load_global_images()
}
return render_context

def get_update_context(self):
update_context = {
"clock": pygame.time.Clock(),
"get_events": pygame.event.get
}
return update_context


class TekmateFactory(object):
def __init__(self, pygame_initializer):
self.pygame_initializer = pygame_initializer

def create(self):
update_context, render_context = self.pygame_initializer.initialize()
game = Game(update_context, render_context)
scene = WorldScene("world")
game.register_new_scene(scene)
game.push_scene_on_stack("world")
return game
56 changes: 2 additions & 54 deletions tekmate/game.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# -*- encoding: utf-8 -*-
from taz.game import Game
from tekmate.items import Item

import pygame
from tekmate.scenes import WorldScene
from tekmate.items import Item


class Player(object):
Expand Down Expand Up @@ -33,57 +30,8 @@ def use_item(self, item1):
return item1.get_use_message()

def move_player(self, mouse_pos):
x = 0
if mouse_pos[0] < self.position[0]:
x = -100
else:
x = 100
self.position = (self.position[0]+x, self.position[1])


class PyGameInitializer(object):
CAPTION = "Tek'ma'te"

def __init__(self, configuration):
self.configuration = configuration

def initialize(self):
pygame.init()
self.set_up_display()
self.set_up_mouse()

return self.get_update_context(), self.get_render_context()

def set_up_display(self):
pygame.display.set_mode((self.configuration["display_width"], self.configuration["display_height"]))
pygame.display.set_caption(self.CAPTION)

def set_up_mouse(self):
pygame.mouse.set_visible(True)

def get_render_context(self):
render_context = {
"flip": pygame.display.flip,
"display": pygame.display.get_surface()
}
return render_context

def get_update_context(self):
update_context = {
"clock": pygame.time.Clock(),
"get_events": pygame.event.get
}
return update_context


class TekmateFactory(object):
def __init__(self, pygame_initializer):
self.pygame_initializer = pygame_initializer

def create(self):
update_context, render_context = self.pygame_initializer.initialize()
game = Game(update_context, render_context)
scene = WorldScene("world")
game.register_new_scene(scene)
game.push_scene_on_stack("world")
return game
self.position = (self.position[0] + x, self.position[1])
20 changes: 12 additions & 8 deletions tekmate/scenes.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
# -*- encoding: utf-8 -*-
import pygame
from taz.game import Scene, Game
from tekmate.ui import PlayerUI

from tekmate.ui import PlayerUserInterface


class WorldScene(Scene):
def __init__(self, ident):
super(WorldScene, self).__init__(ident)
self.player_ui = None

def initialize_scene(self):
self.game.render_context["player_ui"] = PlayerUI()
self.player_ui = PlayerUserInterface()

def update(self): # pragma: no cover (This is only because of all the branches, they will get tested eventually)
player_ui = self.game.render_context["player_ui"]
for event in self.game.update_context["get_events"]():
if event.type == pygame.QUIT or self.escape_key_pressed(event):
raise Game.GameExitException
elif self.left_mouse_button_pressed(event):
player_ui.move_player(event.pos)
self.player_ui.player.move_player(event.pos)
else:
pass

def render(self): # pragma: no cover
self.game.render_context["display"].fill((0, 0, 0))
player_ui = self.game.render_context["player_ui"]
player_ui.render()
self.game.render_context["display"].blit(player_ui.surface, (player_ui.position, player_ui.position))
self.player_ui.render()
self.player_ui.draw_player_to_display(self.game.render_context["display"])

pygame.display.flip()

def resume(self): # pragma: no cover
Expand All @@ -38,4 +42,4 @@ def escape_key_pressed(self, event):
return event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE

def left_mouse_button_pressed(self, event):
return event.type == pygame.MOUSEBUTTONDOWN and event.button == 1
return event.type == pygame.MOUSEBUTTONDOWN and event.button == 1
58 changes: 35 additions & 23 deletions tekmate/ui.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,57 @@
# -*- encoding: utf-8 -*-
from os import path
import pygame
import sys

import os
from os.path import abspath, split, join
import pygame

class ImageNotFound(Exception):
pass
from tekmate.game import Player


class PlayerUI(object):
class PlayerUserInterface(object):
class ImageNotFound(Exception):
pass

SCALING_FACTOR = 2.8

def __init__(self):
self.surface, self.image = self.create_surface_and_image(PlayerUI.SCALING_FACTOR)
self.surface.set_colorkey((0, 128, 128))
self.position = (500, 50)

def render(self): # pragma: no cover
self.surface.fill((250, 250, 250))
self.player = None
self.global_images = None
self.surface = None
self.image = None
self.create_surface_and_image(PlayerUserInterface.SCALING_FACTOR)
self.player = Player()

def render(self):
self.surface.fill((255, 255, 255))
self.surface.blit(self.image, (0, 0))

def draw_player_to_display(self, display): # pragma: no cover
display.blit(self.surface, self.get_position())

def create_surface_and_image(self, factor):
surface = self.create_surface_with_factor(factor)
image = self.create_image_with_factor(factor)
return surface, image
self.create_surface_with_factor(factor)
self.create_image_with_factor(factor)

def create_surface_with_factor(self, factor):
surface_proportions = (round(factor * 50), round(factor * 100))
surface = pygame.Surface(surface_proportions)
surface.convert()
return surface
self.surface = pygame.Surface(surface_proportions)
self.surface.convert()
self.surface.set_colorkey((0, 128, 128))

def create_image_with_factor(self, factor):
image = self.load_image("player", "player.bmp")
img_proportions = (round(factor * image.get_width()), round(factor * image.get_height()))
image = pygame.transform.scale(image, img_proportions)
return image
self.image = self.load_image("player", "player.png")
img_proportions = (int(round(factor * self.image.get_width())), int(round(factor * self.image.get_height())))
self.image = pygame.transform.scale(self.image, img_proportions)

def load_image(self, folder, name_of_file):
fullname = path.join('assets', folder, name_of_file)
pth = abspath(split(__file__)[0])
sys.path.append(abspath(join(pth, u"..")))
fullname = os.path.join(pth, "..", "assets", folder, name_of_file)
try:
return pygame.image.load(fullname)
except:
raise ImageNotFound
raise PlayerUserInterface.ImageNotFound

def get_position(self):
return self.player.position
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# -*- encoding: utf-8 -*-
79 changes: 79 additions & 0 deletions tests/test_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# -*- encoding: utf-8 -*-
from unittest import TestCase

from mock import patch, Mock
import pygame

from tekmate.configuration import PyGameInitializer, TekmateFactory
from tekmate.scenes import WorldScene


class PyGameInitializerTestCase(TestCase):
def setUp(self):
self.conf = {"display_width": 640, "display_height": 480}
self.pygame_initializer = PyGameInitializer(self.conf)
self.pygame_patcher = patch("tekmate.configuration.pygame", spec=True)
self.pygame = self.pygame_patcher.start()
self.uc, self.rc = self.pygame_initializer.initialize()

def test_can_create_pygame_initializer(self):
self.assertIsNotNone(self.pygame_initializer.configuration)

def test_initialze_pygame_actually_initializes_pygame(self):
self.pygame.init.assert_called_with()

def test_initialize_pygame_sets_the_caption(self):
self.pygame.display.set_caption.assert_called_with(PyGameInitializer.CAPTION)

def test_initialize_pygame_sets_window_resoultion_correctly_from_conf(self):
self.pygame.display.set_mode.assert_called_with((640, 480))

def test_initialize_pygame_loads_global_images(self):
self.assertEqual(self.pygame_initializer.load_global_images(), self.rc["images-global"])

def test_when_initialize_mouse_is_getting_configured_correctly(self):
self.pygame.mouse.set_visible.assert_called_with(True)

def test_update_context_should_have_a_clock(self):
self.assertTrue(hasattr(self.uc["clock"], "tick"))

def test_update_context_should_have_get_event_reference(self):
self.assertIs(self.uc["get_events"], self.pygame.event.get)

def test_render_context_should_have_flip_function(self):
self.assertIs(self.rc["flip"], self.pygame.display.flip)

def test_render_context_should_main_surface_reference(self):
self.assertIs(self.rc["display"], self.pygame.display.get_surface())


class TekmateFactoryTestCase(TestCase):
def setUp(self):
mock_init = Mock(spec=PyGameInitializer)
mock_scene = Mock(spec=WorldScene)
mock_init.initialize.return_value = None, {}

self.set_up_display()

self.mock_init = mock_init
self.mock_scene = mock_scene

def set_up_display(self):
pygame.display.init()
pygame.display.set_mode((1, 1))

def assertSceneRegistered(self, identifier, class_type):
game = TekmateFactory(self.mock_init).create()
scene = game.registered_scenes[identifier]
self.assertIsInstance(scene, class_type)

def test_create_should_initialize_pygame(self):
TekmateFactory(self.mock_init).create()
self.mock_init.initialize.assert_called_with()

def test_create_should_add_world_scene_to_game(self):
self.assertSceneRegistered("world", WorldScene)

def test_create_should_push_world_scene_to_game(self):
game = TekmateFactory(self.mock_init).create()
self.assertEqual(game.get_name_of_top_scene(), "world")
Loading

0 comments on commit b788b23

Please sign in to comment.