|  | @@ -15,8 +15,10 @@ from cocos.layer import ScrollableLayer
 | 
	
		
			
			| 15 | 15 |  from cocos.sprite import Sprite
 | 
	
		
			
			| 16 | 16 |  from synergine2.config import Config
 | 
	
		
			
			| 17 | 17 |  from synergine2.log import SynergineLogger
 | 
	
		
			
			|  | 18 | +from synergine2.simulation import Subject
 | 
	
		
			
			| 18 | 19 |  from synergine2.terminals import Terminal
 | 
	
		
			
			| 19 | 20 |  from synergine2.terminals import TerminalPackage
 | 
	
		
			
			|  | 21 | +from synergine2.xyz import XYZSubjectMixin
 | 
	
		
			
			| 20 | 22 |  from synergine2_cocos2d.actor import Actor
 | 
	
		
			
			| 21 | 23 |  from synergine2_cocos2d.exception import OuterWorldPosition
 | 
	
		
			
			| 22 | 24 |  from synergine2_cocos2d.layer import LayerManager
 | 
	
	
		
			
			|  | @@ -601,6 +603,47 @@ class MainLayer(ScrollableLayer):
 | 
	
		
			
			| 601 | 603 |          self.px_height = height
 | 
	
		
			
			| 602 | 604 |  
 | 
	
		
			
			| 603 | 605 |  
 | 
	
		
			
			|  | 606 | +class SubjectMapper(object):
 | 
	
		
			
			|  | 607 | +    def __init__(
 | 
	
		
			
			|  | 608 | +        self,
 | 
	
		
			
			|  | 609 | +        actor_class: typing.Type[Actor],
 | 
	
		
			
			|  | 610 | +    ) -> None:
 | 
	
		
			
			|  | 611 | +        self.actor_class = actor_class
 | 
	
		
			
			|  | 612 | +
 | 
	
		
			
			|  | 613 | +    def append(
 | 
	
		
			
			|  | 614 | +        self,
 | 
	
		
			
			|  | 615 | +        subject: XYZSubjectMixin,
 | 
	
		
			
			|  | 616 | +        layer_manager: LayerManager,
 | 
	
		
			
			|  | 617 | +    ) -> None:
 | 
	
		
			
			|  | 618 | +        actor = self.actor_class()
 | 
	
		
			
			|  | 619 | +        pixel_position = layer_manager.grid_manager.get_pixel_position_of_grid_position((
 | 
	
		
			
			|  | 620 | +            subject.position[0],
 | 
	
		
			
			|  | 621 | +            subject.position[1],
 | 
	
		
			
			|  | 622 | +        ))
 | 
	
		
			
			|  | 623 | +        actor.update_position(euclid.Vector2(*pixel_position))
 | 
	
		
			
			|  | 624 | +
 | 
	
		
			
			|  | 625 | +        # TODO: Selectable nature must be configurable
 | 
	
		
			
			|  | 626 | +        layer_manager.add_subject(actor)
 | 
	
		
			
			|  | 627 | +        layer_manager.set_selectable(actor)
 | 
	
		
			
			|  | 628 | +
 | 
	
		
			
			|  | 629 | +
 | 
	
		
			
			|  | 630 | +class SubjectMapperFactory(object):
 | 
	
		
			
			|  | 631 | +    def __init__(self) -> None:
 | 
	
		
			
			|  | 632 | +        self.mapping = {}  # type: typing.Dict[typing.Type[XYZSubjectMixin], SubjectMapper]
 | 
	
		
			
			|  | 633 | +
 | 
	
		
			
			|  | 634 | +    def register_mapper(self, subject_class: typing.Type[XYZSubjectMixin], mapper: SubjectMapper) -> None:
 | 
	
		
			
			|  | 635 | +        if subject_class not in self.mapping:
 | 
	
		
			
			|  | 636 | +            self.mapping[subject_class] = mapper
 | 
	
		
			
			|  | 637 | +        else:
 | 
	
		
			
			|  | 638 | +            raise ValueError('subject_class already register with "{}"'.format(str(self.mapping[subject_class])))
 | 
	
		
			
			|  | 639 | +
 | 
	
		
			
			|  | 640 | +    def get_subject_mapper(self, subject: XYZSubjectMixin) -> SubjectMapper:
 | 
	
		
			
			|  | 641 | +        for subject_class, mapper in self.mapping.items():
 | 
	
		
			
			|  | 642 | +            if isinstance(subject, subject_class):
 | 
	
		
			
			|  | 643 | +                return mapper
 | 
	
		
			
			|  | 644 | +        raise KeyError('No mapper for subject "{}"'.format(str(subject)))
 | 
	
		
			
			|  | 645 | +
 | 
	
		
			
			|  | 646 | +
 | 
	
		
			
			| 604 | 647 |  class Gui(object):
 | 
	
		
			
			| 605 | 648 |      def __init__(
 | 
	
		
			
			| 606 | 649 |              self,
 | 
	
	
		
			
			|  | @@ -630,6 +673,8 @@ class Gui(object):
 | 
	
		
			
			| 630 | 673 |          pyglet.gl.glEnable(pyglet.gl.GL_ALPHA_TEST)
 | 
	
		
			
			| 631 | 674 |          pyglet.gl.glAlphaFunc(pyglet.gl.GL_GREATER, .1)
 | 
	
		
			
			| 632 | 675 |  
 | 
	
		
			
			|  | 676 | +        self.subject_mapper_factory = SubjectMapperFactory()
 | 
	
		
			
			|  | 677 | +
 | 
	
		
			
			| 633 | 678 |      def run(self):
 | 
	
		
			
			| 634 | 679 |          self.before_run()
 | 
	
		
			
			| 635 | 680 |          pyglet.clock.schedule_interval(
 | 
	
	
		
			
			|  | @@ -681,4 +726,14 @@ class TMXGui(Gui):
 | 
	
		
			
			| 681 | 726 |          self.layer_manager.center()
 | 
	
		
			
			| 682 | 727 |  
 | 
	
		
			
			| 683 | 728 |      def get_main_scene(self) -> cocos.cocosnode.CocosNode:
 | 
	
		
			
			| 684 |  | -        return self.layer_manager.main_scene
 | 
	
		
			
			|  | 729 | +        return self.layer_manager.main_scene
 | 
	
		
			
			|  | 730 | +
 | 
	
		
			
			|  | 731 | +    def before_received(self, package: TerminalPackage):
 | 
	
		
			
			|  | 732 | +        super().before_received(package)
 | 
	
		
			
			|  | 733 | +        if package.subjects:  # They are new subjects in the simulation
 | 
	
		
			
			|  | 734 | +            for subject in package.subjects:
 | 
	
		
			
			|  | 735 | +                self.append_subject(subject)
 | 
	
		
			
			|  | 736 | +
 | 
	
		
			
			|  | 737 | +    def append_subject(self, subject: XYZSubjectMixin) -> None:
 | 
	
		
			
			|  | 738 | +        subject_mapper = self.subject_mapper_factory.get_subject_mapper(subject)
 | 
	
		
			
			|  | 739 | +        subject_mapper.append(subject, self.layer_manager)
 |