Skip to content

Commit

Permalink
Merge pull request #2 from TheArtur128/cloud-package
Browse files Browse the repository at this point in the history
2.0.0 version code
  • Loading branch information
emptybutton committed Nov 10, 2022
2 parents 1864de7 + 1d0585d commit 36d2472
Show file tree
Hide file tree
Showing 26 changed files with 4,923 additions and 2,245 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
Helps to create games without limiting you

### Advantages
* **Speed**. You will very quickly start writing simulations without paying attention to the infrastructure (but you can also tailor it to your needs)
* **Integration**. You can quickly connect the engine to an already created game
* **Flexibility**. You are not even limited to 2 or 3 dimensions!
* **High Cohesion**. Don't overthink the whole game
* **Pygame integration**. Pygame render out of the box
* **Speed** - You will very quickly start developing without paying attention to the infrastructure (but you can also tailor it to your needs)
* **Connectability** - You can quickly connect the engine to an already created game
* **Flexibility** - You are not even limited to 2 or 3 dimensions!
* **Controllability** - You can incredibly deftly operate with the logic of your game
* **Fullness** - Integration with pygame rendering solution

### Installation
`pip install sim32`
Empty file removed errors/__init__.py
Empty file.
13 changes: 13 additions & 0 deletions errors/avatar_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from sim32.errors.core_errors import UnitError


class AvatarError(UnitError):
pass


class AnimationError(AvatarError):
pass


class AnimationAlreadyFinishedError(AnimationError):
pass
16 changes: 10 additions & 6 deletions errors/core_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,31 @@ class UnsupportedProcessError(ProcessKeeperError):
pass


class UnitError(SimulationError):
class InteractionError(SimulationError):
pass


class UnitRelationError(UnitError):
class UnmetDependencyError(SimulationError):
pass


class DiscreteUnitError(UnitError):
class WorldInhabitantsHandlerError(SimulationError):
pass


class NotSupportPartError(DiscreteUnitError):
class UnsupportedInhabitantForHandlerError(WorldInhabitantsHandlerError):
pass


class UnitError(SimulationError):
pass


class UnitPartError(UnitError):
class DiscreteError(SimulationError):
pass


class UnsupportedUnitForHandlerError(UnitError):
class NotSupportPartError(DiscreteError):
pass


Expand Down
4 changes: 4 additions & 0 deletions errors/geometry_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ class GeometryError(Exception):
pass


class AxisPlaneDegreesError(GeometryError):
pass


class VectorError(GeometryError):
pass

Expand Down
89 changes: 52 additions & 37 deletions example/__init__.py → examples/pygame_integration.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from pygame import *
from random import randint, choice

from sim32.avatars import ResourceAvatar, PrimitiveAvatar
from sim32.core import *
from sim32.pygame_renders import *
from sim32.tools import Timer
from sim32.pygame_integration import *


class MainHeroManagement(PygameEventHandler, EventSupportStackHandler):
Expand All @@ -23,23 +24,26 @@ class MainHeroManagement(PygameEventHandler, EventSupportStackHandler):
def __init__(self, main_hero: InfinitelyImpulseUnit):
self.main_hero = main_hero

def _handle(self, event: PygameEvent, loop: PygameLoopUpdater) -> None:
def _handle(self, event: PygameEvent, loop: HandlerLoop) -> None:
impulse = Vector((0, 0))

if event.key in self._right_movement_keys:
impulse += Vector((self.main_hero.speed, 0))
impulse += Vector((self.main_hero._speed_limit, 0))
if event.key in self._left_movement_keys:
impulse -= Vector((self.main_hero.speed, 0))
impulse -= Vector((self.main_hero._speed_limit, 0))

if event.key in self._up_movement_keys:
impulse -= Vector((0, self.main_hero.speed))
impulse -= Vector((0, self.main_hero._speed_limit))
if event.key in self._down_movement_keys:
impulse += Vector((0, self.main_hero.speed))
impulse += Vector((0, self.main_hero._speed_limit))

self.main_hero.impulse = impulse
self.main_hero.moving_process.original_process.vector_to_next_subject_position = impulse


class TestUnit(SpeedKeeperMixin, InfinitelyImpulseUnit):
class TestObject(MultilayerProcessMovableAvatarKeeper):
_moving_process_factory = AbruptImpulseProcess
_proxy_moving_process_factories = (CustomFactory(SpeedLimitedProxyMovingProcess, 2), )

_avatar_factory = CustomFactory(
lambda unit: PrimitiveAvatar(
unit,
Expand All @@ -49,81 +53,92 @@ class TestUnit(SpeedKeeperMixin, InfinitelyImpulseUnit):
)
)
)
_speed = 2

def update(self) -> None:
pass


class ObserveUnitAvatar(ResourceAvatar):
class ObserveAvatar(ResourceAvatar):
_resource_factory = CustomFactory(lambda _: Circle(RGBAColor(255, 0, 50), 0))

def update(self) -> None:
super().update()
vector_to_observed_unit = self.unit.position - self.unit.observed_unit.position
self.render_resource.radius = vector_to_observed_unit.length
vector_to_observed = self.domain.position - self.domain.observed.position
self.render_resource.radius = vector_to_observed.length


class ObserveUnit(SpeedKeeperMixin, ImpulseUnit):
_avatar_factory = ObserveUnitAvatar
_speed = 1
class ObserveUnit(MultilayerProcessMovableAvatarKeeper, IUpdatable):
_avatar_factory = ObserveAvatar

def __init__(self, position: Vector, observed_unit: PositionalUnit):
_moving_process_factory = AbruptImpulseProcess
_proxy_moving_process_factories = (CustomFactory(SpeedLimitedProxyMovingProcess, 1), )

def __init__(self, position: Vector, observed: IPositional):
super().__init__(position)
self.observed_unit = observed_unit
self.observed = observed

def update(self) -> None:
vector_to_observed_unit = Vector(
(self.observed_unit.position - self.position).coordinates
)
self.impulse = vector_to_observed_unit / (
(vector_to_observed_unit.length / self.speed)
if vector_to_observed_unit.length else 1
self._moving_process.original_process.vector_to_next_subject_position = (
self.observed.position
- self.position
)


class UnitSpawner(PositionalUnit, MultitaskingUnit):
class SpawnerUnit(StaticAvatarKeeper, MultitaskingUnit):
_avatar_factory = CustomFactory(lambda unit: PrimitiveAvatar(unit, None))

def __init__(
self,
position: Vector,
unit_factory: Callable[[Vector], PositionalUnit],
spawn_zone: Iterable[range, ],
factory: Callable[[Vector], IPositional],
spawn_zone: Iterable[Diapason],
timer: Timer
):
super().__init__(position)
super(MultitaskingUnit, self).__init__()

self.unit_factory = unit_factory
self.factory = factory
self.spawn_zone = tuple(spawn_zone)
self.timer = timer

def update(self) -> None:
if self.timer.is_time_over():
generate_point = Vector(tuple(
randint(coordinate_range.start, coordinate_range.stop)
for coordinate_range in self.spawn_zone
randint(coordinate_diapason.start, coordinate_diapason.end)
for coordinate_diapason in self.spawn_zone
))

self.add_process(
UnitSpawnProcess((self.unit_factory(generate_point), ))
UnitSpawnProcess((self.factory(generate_point), ))
)
self.timer.start()


black_unit = TestUnit(Vector((200, 240)))
black_unit = TestObject(Vector((200, 240)))
black_unit.avatar.render_resource = Circle(RGBAColor(), 20)

red_unit = ObserveUnit(Vector((100, 240)), black_unit)

unit_spawner = UnitSpawner(Vector((320, 240)), CustomFactory(TestUnit), (range(640), range(480)), Timer(3))
unit_spawner = SpawnerUnit(
Vector((320, 240)),
CustomFactory(TestObject),
(Diapason(640), Diapason(480)),
Timer(3)
)

unit_spawner.avatar.render_resource = Circle(RGBAColor(red=255, green=243), 30)

CustomAppFactory(PygameLoopFactory([ExitEventHandler(), MainHeroManagement(black_unit)], 60))(

CustomAppFactory((
CustomFactory(
SyncPygameEventController, (
ExitEventHandler(),
MainHeroManagement(black_unit)
)
),
PygameDisplayUpdater,
CustomFactory(PygameClockSleepLoopHandler, 60)
))(
CustomWorld(
[black_unit, red_unit, unit_spawner],
[UnitUpdater, WorldProcessesActivator, UnitMover, RenderResourceParser]
[InhabitantUpdater, WorldProcessesActivator, InhabitantMover, InhabitantAvatarRenderResourceParser]
),
(
PygameSurfaceRender(
Expand Down
141 changes: 141 additions & 0 deletions examples/snake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
from abc import ABC
from typing import Optional, Callable, Iterable

from colorama import init, Fore

from sim32.avatars import PrimitiveAvatar
from sim32.core import *
from sim32.renders import ConsoleCell, ConsoleRender
from sim32.geometry import Vector, AxisPlaneDegrees, DegreeMeasure
from sim32.tools import CustomFactory, Diapason, Arguments


init(autoreset=True)


class Snake(DiscreteUnit):
_part_attribute_names = ('_head', '_tails')

_head: Optional[MovablePositionalKeeper] = None
_tails: Iterable = tuple()

@property
def head(self) -> Optional[MovablePositionalKeeper]:
return self._head

@property
def tails(self) -> tuple[ProcessMovablePositionalKeeper]:
return tuple(self._tails)

def init_parts(
self,
head: MovablePositionalKeeper,
tail_factory: Callable[[Vector], ProcessMovablePositionalKeeper],
) -> None:
self._tails = list()
self._head = head
self._tail_factory = tail_factory

def grow_tail(self, tail_length: int) -> None:
for _ in range(tail_length):
last_node = self._tails[-1] if self._tails else self._head

self._tails.append(self._tail_factory(last_node.previous_position))

def cut_tail(self, tail_length: int) -> None:
self._tails = self._tails[:-tail_length]

def update(self) -> None:
for tail_index, tail in enumerate(self._tails):
if not isinstance(tail.moving_process.original_process, DirectedMovingProcess):
continue

previous_unit = self.__get_prevous_node_by(tail_index)

tail.moving_process.original_process.vector_to_next_subject_position = (
previous_unit.position - tail.position
)

def __get_prevous_node_by(self, tail_index: int) -> MovablePositionalKeeper:
return self._head if tail_index - 1 < 0 else self._tails[tail_index - 1]


class SnakeHead(MultilayerProcessMovableAvatarKeeper):
_avatar_factory = CustomFactory(PrimitiveAvatar, ConsoleCell('#', Fore.LIGHTBLUE_EX))

_moving_process_factory = AbruptImpulseProcess
_proxy_moving_process_factories = (CustomFactory(SpeedLimitedProxyMovingProcess, 1), )


class SnakeTail(MultilayerProcessMovableAvatarKeeper):
_avatar_factory = CustomFactory(PrimitiveAvatar, ConsoleCell('#', Fore.LIGHTWHITE_EX))

_moving_process_factory = DirectedMovingProcess
_proxy_moving_process_factories = (CustomFactory(SpeedLimitedProxyMovingProcess, 1), )


class SnakeEvent(Process, ABC):
def __init__(self, snake: Snake):
super().__init__()
self.snake = snake

@property
def participants(self) -> tuple[Snake]:
return (self.snake, )


class SnakeTailLengthKepeerEvent(SnakeEvent):
def __init__(self, snake: Snake, tail_length_diapason: Diapason, tail_number: int = 1):
super().__init__(snake)
self.tail_number = tail_number
self.tail_length_diapason = tail_length_diapason

def _handle(self) -> None:
if len(self.snake.tails) == self.tail_length_diapason.start:
self.__is_growing_mode = True

elif len(self.snake.tails) >= self.tail_length_diapason.end:
self.__is_growing_mode = False

getattr(self.snake, 'grow_tail' if self.__is_growing_mode else 'cut_tail')(self.tail_number)

__is_growing_mode: bool = True


class SnakeHeadTurnEvent(SnakeEvent, DelayedProcess):
_ticks_of_inactivity: int = 10

def start(self) -> None:
super().start()
self._activate_snake_head_moving()

def _handle(self) -> None:
self._activate_snake_head_moving()
self.__snake_head_vector = self.__snake_head_vector.get_rotated_by(
AxisPlaneDegrees(0, 1, DegreeMeasure(90))
)

self.activate_delay()

def _activate_snake_head_moving(self) -> None:
self.snake.head.moving_process.original_process.vector_to_next_subject_position = self.__snake_head_vector

__snake_head_vector = Vector((1, 0))


snake_factory = CustomDiscreteUnitFactory(
Snake,
Arguments.create_via_call(SnakeHead(Vector((10, 8))), SnakeTail)
)

snake = snake_factory()
snake.grow_tail(5)


CustomAppFactory([CustomFactory(StandardSleepLoopHandler, 0.5)])(
CustomWorld(
[SnakeHeadTurnEvent(snake), SnakeTailLengthKepeerEvent(snake, Diapason(2, 9)), snake],
[InhabitantMover, InhabitantUpdater, InhabitantAvatarRenderResourceParser]
),
(ConsoleRender(ConsoleCell('.')), )
).run()
Loading

0 comments on commit 36d2472

Please sign in to comment.