Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Brand new object system #38

Open
pkulev opened this issue Jan 15, 2017 · 6 comments
Open

Brand new object system #38

pkulev opened this issue Jan 15, 2017 · 6 comments

Comments

@pkulev
Copy link
Owner

pkulev commented Jan 15, 2017

THIS IS DRAFT

Abstract

This time not came yet, but some changes we need to do in order to unblock further development.
We need to design and implement as simple as possible object system that will fit to our needs for this time.
We have ships and backgrounds that have Surface to render. We have projectiles that looks like not good designed lists of coordinates...

Design

GameObject and State

  • GameObject is recursive data structure that have position in world coordinates if it is not part of another object, otherwise it has local coordinates as offset to parent object.
  • Each GameObject can hold subobjects of type GameObject with own colliders, animations, sprites.
  • State as implemented now is a scene, that holds game objects and does all interations with them in loop when this state is active.
  • State can hold many instances of GameObject.

Appllication and States

  • Application holds one or more States and executes current state.
  • Only one State can be used in one time.
  • Apllication calls in the IOLoop 3 methods of current State object: events(), update(dt), and render().

Event-based messaging

  • Every State has it's own message queue to provide messaging between objects and maybe even whole engine subsystems.
  • (Optional) Application can have dedicated queue for something.
  • GameObject can put event into queue via it's State.
  • EventHandler of State pops all events from queue and process them on events stage of the State.

Game-specific implementation examples

Ship

class PlayerShip(Renderable):
    def __init__(self, ...):
         self.add(WeaponSlot(transform, ...))  # transform is offset
         self.add(WeaponSlot(transform. ...))  # that applied to PlayerShip's transform
         self.add(LeftEngine(transform, ...))  # maybe some form of declarative definition

class InGameState(State):
    def __init__(self, owner):
        self._actor = PlayerShip(transform, ... )
        self.add(self._actor)  # will be rendered and updated

class InGameEventHandler(Handler):
     def handle(self):
          # after input
          for event in self.owner.get_events():
              if event.recepient:
                  self.dispatch(event)
              # some other things
              

Weapon

class Weapon(Renderable):
    def update(self):
        if self._fire:
            self.add(Projectile(self))
        ...

Collision detection

class RocketProjectile(...):
    def on_trigger_enter(collider):
        if self.side != collider.game_object.side and collider.game_object.side != "obstacles":
            collider.game_object.apply_damage(self)
            ...
@pkulev pkulev added this to the Working alpha version milestone Jan 15, 2017
@pkulev pkulev self-assigned this Jan 15, 2017
@alex-eg
Copy link
Contributor

alex-eg commented Mar 8, 2017

Are you sure it absolutely must be implemented in scope of current milestone?

@pkulev
Copy link
Owner Author

pkulev commented Apr 23, 2017

class Transform(object):
    """t"""

    required = True

    def __init__(self, pos=None, rot=None, scale=None):
        self._pos = pos or Point()
        self._rot = rot or Point()
        self._scale = scale or Point(1, 1, 1)


class GameObject(object):
    """t"""

    default_components = [Transform]
    components = default_components[:]

    def __init__(self, transform=None):
        self.add_component(transform or Transform())

    def add_component(self, component):
        """t"""
        self.components.append(component)

@pkulev
Copy link
Owner Author

pkulev commented Apr 27, 2017

@dispatch(Ship, Projectile)
def on_collision(ship, projectile):
    ship.apply_damage(projectile.damage)

@dispatch(EnemyShip, EnemyShip)
def on_collision(ship1, ship2):
    pass

@alex-eg
Copy link
Contributor

alex-eg commented Apr 28, 2017

It's shame that we cannot construct function in runtime. It would be very nice to just have something like defcollision for collision detection.

@pkulev pkulev removed this from the Working prototype milestone Dec 1, 2018
@pkulev
Copy link
Owner Author

pkulev commented Mar 7, 2020

diff --git a/xoinvader/menu.py b/xoinvader/menu.py
index 16e0710..eb8d801 100644
--- a/xoinvader/menu.py
+++ b/xoinvader/menu.py
@@ -41,6 +41,62 @@ class PauseMenuState(State):
             KEY.N: lambda: self.notify("This is test notification"),
         })
 
+    def key_event_map(self):
+        # Under the hood
+        # self._events = EventHandler(self, self.key_event_map)
+        # dispatch(event)
+        # if action == call-app then getattr(application.get_current(), target)(*args, **kwargs)
+        # if action == call-self then getattr(self, target)(*args, **kwargs)
+        # if action == call then parse()
+        {
+            "type": "State",
+            "name": "PauseMenuState",
+            "init": {
+                "objects": [
+                    {"class": "TextWidget", "args": ([4, 4], "Pause")},
+                    {"class": "MenuItemWidget", "args": ([10, 10], "Continue")},
+                    {"class": "MenuItemWidget", "args": ([10, 11], "Quit")},
+                ],
+            },
+            "key-event-map": {
+                "KEY.ESCAPE": {
+                    "action": "call-app",
+                    "target": "stop",
+                },
+                "KEY.R": {
+                    "action": "call-self",
+                    "target": "notify",
+                    "args": "This is test notification",
+                },
+                "KEY.N": {
+                    "action": "trigger-state",
+                    "target": "InGameState",
+                },
+            },
+            "scripts": [
+                {
+                    "name": "notify.py",
+                    "id": "{fdfdfdf}",
+                },
+            ],
+        }

     def notify(self, text, pos=Point(15, 15)):
         self.add(
             PopUpNotificationWidget(

@alex-eg
Copy link
Contributor

alex-eg commented Mar 9, 2020

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants