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

Models? #1

Open
JenkinJoe opened this issue May 1, 2016 · 9 comments
Open

Models? #1

JenkinJoe opened this issue May 1, 2016 · 9 comments

Comments

@JenkinJoe
Copy link

Hello there,

what are the models in karma?

@cgarciae
Copy link
Owner

cgarciae commented May 4, 2016

@JenkinJoe The models are normal C# classes. Depending on how/what you are doing you wont need them, maybe your presenter or controller just defines those fields. I use them mostly to parse json that comes from the server.

@JenkinJoe
Copy link
Author

JenkinJoe commented May 14, 2016

@cgarciae Assuming that we have a Player Controller & Presenter. How do you handle several different logic behaviors like Player's Camera, Movement, Physics or Animations if you are doing it the "karmic" way? - Placing everything into the controller seems confusing for me especially if you intend to separate Settings per behavior.

@cgarciae
Copy link
Owner

@JenkinJoe The philosophy is to use composition. You create other presenters for e.g. the camera, the characters, ect, and request them via dependency injection. You can create special presenters called elements which are intented to appear in view but they themselves are not views, that is, you cant request them through the router. I'll post 2 videos today about this.

@JenkinJoe
Copy link
Author

JenkinJoe commented May 14, 2016

@cgarciae Yes that's true. But what I intended to achieve is having lossless coupled scripts fullfilling different tasks like those described above. And i did already use Elements for other things such as a Screen Fader or Audio Sources. But doing the same on the player's scripts would result in having redundant instantiated prefabs that do not perform a task. What i really want is a player controller that uses all of those scripts and combines them into one action e.g. walking with animations and physics.

So what i was thinking about is more zenject related. By defining something like this in the App\startup.cs:

public class Startup : App, ICApp
{
    [SerializeField]
    Settings _settings = null;
    public DiContainer container { get; private set; }

    public override void Configure(IApplication app, DiContainer container)
    {
        this.container = container;
        container.Bind<ICApp>().ToInstance(this);

        InstallSettings();
    }

    public override void Init(IRouter router, DiContainer container)
    {
        router.GoTo(MenuPresenter.view);
    }

    public override void OnPresenterDestroy()
    {

    }

    public void InstallSettings()
    {
        container.Bind<PlayerPresenter.Camera.Settings>().ToSingleInstance(_settings.Player.Camera);
    }

}

[Serializable]
public class Settings
{
    public PlayerSettings Player;
    [Serializable]
    public class PlayerSettings
    {
        public PlayerPresenter.Camera.Settings Camera;
    }
}

public interface ICApp{}

And in the PlayerPresenter:

public PlayerPresenter.Camera.Settings settings { get; private set; }
public void PostConstructor(ICApp _app, DiContainer container, PlayerController controller, PlayerPresenter.Camera.Settings settings)
    {
        this.app = (MVCPresenter)_app;
        this.container = container;
        this.controller = controller;
        this.settings = settings;

        controller.PostConstructor(this);
    }
public class Camera
    {
        public Settings settings;
        public Camera(Settings settings)
        {
            this.settings = settings;
        }

        [Serializable]
        public class Settings
        {
            public int zoomRate = 200;
            public float
                playerHeight = 2.0f,
                playerDistance = 3.0f,
                minDistance = 2.0f,
                maxDistance = 10.0f,
                zoomDampening = 5.0f,
                xSpeed = 200.0f,
                ySpeed = 200.0f,
                rotationDampening = 3.0f,
                offsetFromWall = 0.1f,
                fpsCamDist = -0.15f;
            public bool canControl = true;

            public LayerMask collisionLayers = -1;

            public enum CameraState
            {
                FirstPerson,
                ThirdPerson,
                Orbit
            }
            public CameraState camState = CameraState.FirstPerson;

            public Transform cam = null;
            public Transform headBone = null;
        }
    }

So I can use it in the PlayerController, like this:

internal void Init()
{
        Debug.Log(presenter.settings.fpsCamDist);
 }

The script above does only use settings passed by startup.cs : Settings to the PlayerPresenter.

Another thing that came up to my mind is to handle camera,animation,movement and physics as services (singleton therefore) in the Player Presenter, which is an element itself and only use the methods/settings in those service classes. That way you can still decide how the Presenter (Player in this case) will handle its movement by either use components of those services or not.
Doing this it's possible to have whole movement covering services for different types of enemies/players.

A more convenient way would be to nest different elements (Camera, Physics,...) inside one main element (Player Presenter). But then there would be the already mentioned problem with redundant game objects in the scene. Is it somehow possible to use different elements on the same gameObject?

edit
I found a good solution for this.
See https://github.com/modesttree/Zenject#sub-containers-and-facades

@JenkinJoe
Copy link
Author

Could you please make a usage example for layouts in Karma?
I don't like to use Facades if there's already a mvpc pattern that could handle this.

@cgarciae
Copy link
Owner

@JenkinJoe Sorry about the delay.
I am uploading 2 videos about doing general stuff. I'll try to record a third about layouts tomorrow and update this repo.

@cgarciae
Copy link
Owner

@JenkinJoe
Copy link
Author

JenkinJoe commented May 21, 2016

Alright pal, thanks. I'm glad that you actually respond finally ;)
What I'm really missing is the tree structure of dependencies you have in angularjs 2.
It's possible to reconstruct that behavior with Zenject's Facades and Sub-Container. But i thought that karma's layouts could do something near. From what I've understood layouts in karma do only parenting children presenters. Do they also provide the same instance of dependencies for them?
Also for some reason i couldn't get those layouts to work for me. What I've tried was:

using UnityEngine;
using UnityEngine.Events;

using System.Collections;
using Karma;
using System;
using Karma.Metadata;
using Zenject;

[Layout(view)]
public class StartPresenter : MVCPresenter
{
    public const string view = "start";

    public Settings settings { get; private set; }
    public MVCPresenter app { get; private set; }
    public DiContainer container { get; private set; }
    private StartController controller;
    public StartEnvironmentPresenter environmentPresenter;
    public IRouter router { get; private set; }

    [PostInject]
    public void PostConstructor(IRouter router, ICApp _app, DiContainer container, StartController controller, Settings settings, StartEnvironmentPresenter environment)
    {
        this.router = router;
        this.app = (MVCPresenter)_app;
        this.container = container;
        this.controller = controller;
        this.settings = settings;
        this.environmentPresenter = environment;

        controller.PostConstructor(this);
    }

    public override void OnPresenterDestroy()
    {

    } 
}

@cgarciae
Copy link
Owner

cgarciae commented May 22, 2016

@JenkinJoe
Here is the skeleton of a layout

    [Layout(view)]
    public class MyLayoutPresenter : MVCPresenter
    {
        public const string view = "my-layout";

        public Transform _root3D;
        public Transform _inner3D;
        public RectTransform _innerUI;
        public RectTransform _rootUI;

        public override RectTransform rootUI { get { return _rootUI; } }
        public override Transform inner3D { get { return _inner3D; } }
        public override Transform root3D { get { return _root3D; } }
        public override RectTransform innerUI { get { return _innerUI; }}

        [PostInject]
        public void Constructor(....)
        {
            //code
        } 

        public override void OnPresenterDestroy()
        {
             //code
        }

rootUI, inner3D, root3D and innerUI are optional overrides of every MVCPresenter, they dictate how nesting will be done. The behavoiur is as follows:

  • The parent of the Presenter's rootUI will be set to the Layout's innerUI.
  • The parent of the Presenter's root3D will be set to the Layout's inner3D.

If your view is simple enough you might only need to override innerUI on the Layout. By default all these properties are set to this.transform.

You will also need to enable the use of layouts for your app on the Configure method:

        public override void Configure(IApplication app, DiContainer container)
        {
            ...
            app.UseLayout(true);
            ...
        }

Finally, the prefab of your layout will need to exist under App/Prefabs/Resources/layouts as my-layout.

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

No branches or pull requests

2 participants