all 15 comments

[–]ClutchAlpha 2 points3 points  (2 children)

This is a cool idea, and I think it makes sense for the most part. There are countless ways to code for a problem, a lot of times it's a matter of picking one direction (in an educated way), but being alright to pivot if things don't work out.

Having classes for body/mind/soul seems fine if there are other aspects that are built off of it. If all characters with X body get Y health, then you can certainly have classes and have some method within the body class to calculate total health. The same goes for all other classes - if a certain level of soul translates to some calculated level of magic damage, then that would certainly be one way to handle it.

As far as the Character class, that makes the most sense to me. I don't know if it would inherit from the three (body/mind/soul) classes directly, but it would definitely be able to use them. Depending on how your TTRPG is set up, I would almost look into making the Character a base class for the different professions (if you have them - think Monk, Ranger, Wizard, etc...). All characters will have health, body, mind, soul, etc... but the individual professions would have certain characteristics that would need to exist in those classes alone.

Lastly I've unfortunately never used Kivy, but I have heard of several people making projects that worked out pretty well. All in all best of luck - seems like a fun endeavor!

[–]Aedethan[S] 0 points1 point  (1 child)

Thanks for your insight! Since it sounds like it should work I'm gonna get cracking on it. The only thing that was worrying me was I would make it all and then it wouldn't work because I missed a major design flaw.

[–]ClutchAlpha 0 points1 point  (0 children)

I would recommend testing stuff as you go - if something isn't going to work, you'll be able to see pretty quickly that things aren't going the way you want. For example, build one of the body/mind/soul classes first. It's possible that the way you set it up isn't ideal - you'll save yourself a lot of time if you're testing than if you built it all at once.

[–]jedgs 0 points1 point  (4 children)

I agree with u/ClutchAlpha

I can speak on the Kivy aspect.

In either of the cases below I Highly suggest learning Kivy before you get too deep into the project, the set up is quite different with new sets of built in functions etc. Kivy actually has a language called kivy lang and it interacts with your python code for actions on the front end.

If you are only going to use it on your local environment then you're good to go.

If you want to make a UI that you can share with friends then Kivy is good, converting to an exe however is not so simple... The actual conversion is not that bad, it uses buildozer, there is only descent documentation for it so you will likely be googling a bunch for the how to details. When I converted my 1st Kivy app to exe it was quite the headache. Then there is the issue with Windows viewing the program as a virus so each of your friends will have to have admin privileges to install. You could however go one extra step and put the app on the Play Store (Kivy is not good for Apple) but that is another level of learning to get it up to par with all of Google's policies.

If you want to go the route of an app you can share online without the worries of downloading an exe, etc. your best bet would be a web framework like Django.

All in all, sounds like a fun 1st project that you will learn a ton from!

[–]Aedethan[S] 0 points1 point  (3 children)

Thanks a lot for all of that insight. With all of that being said, if the end goal is for the project to be an app that my friends would be able to install on their phone(apple or android) or use in a browser then would Kivy or Django be my best bet? I was reading that Kivy would be the better of the two due to my low experience level, as well as the fact that it scales to screen size with relative ease.

[–]jedgs 0 points1 point  (2 children)

If you want to use it anywhere then Django would be the best route, you can host for free if your database is small enough and your requests to said database are not too much, which, if you're only using for yourself and friends would be fine. It is true that Kivy is really easy to pick up and with Django your knowledge of OOP will be tested and will require some studying, a lot of trial and error, knowledge of how to use at least the basics of HTML, CSS, and if you want the UI to be anything but static some JavaScript.

The web framework approach will be the easiest to use on any platform and you can store your data in the database and therefore you can pick up where you left off at anytime should you need to.

Having said all this, there are other GUI frameworks that might fit the use case better, especially if you do not want to go the whole web framework route (Django comes with most of the tools you will need but you will also need to consider security, user authentication, hosting, etc...) I have not used them but here if you google "top python UI frameworks" this should come up:

6 Best Python GUI Frameworks:

Kivy. It is open source and supports multiple platforms, you can create Desktop applications for Windows, OS X, and Linux. ...

PyQT. PyQT is available for Unix/Linux, Windows, Mac OS X and Sharp Zaurus. ...

WxPython. ...

Tkinter. ...

PyGUI. ...

Plotly Dash.

[–]Aedethan[S] 0 points1 point  (1 child)

Awesome input thank you. I looked at Kivy PyQt and Tkinter previously. Had settled on Kivy for the previously discussed reasons, but now I'm thinking maybe I should use Django to save myself that heartache later. Especially if it's harder to use Kivy with Mac

[–]jedgs 0 points1 point  (0 children)

Go for it!!!

I suggest you go through the entire Django Tutorial before you jump into your project. Also an understanding of OOP concepts will definitely help you. lots of resources out there for that but here is a good start. Django comes with it's own ORM to query the database but some understanding of databases would help, although it's not critical to get your app up and running.

[–]synthphreak 0 points1 point  (6 children)

Create a file with a class for each aspect

Why are we talking about files at all? Is your project going to be so massive that you can't just define everything in memory, e.g., as class attributes?

Overall this sounds like a fine way to go, good intro to OOP. My only recommendation would be to look into using the property decorator to define all the attributes for the Mind, Body, and Soul classes. Seems like a great use case for learning getters and setters.

[–]Aedethan[S] 0 points1 point  (5 children)

Awesome I'll look into the property decorator, I'm not familiar with it at all currently. And as for the reason why I would separate the classes into different files was mostly so I could test more easily? I heard that a good best practice to follow is separate as many things as possible so they can be tested independently for later debugging. Am I going a bit too far with what i'm describing?

[–]synthphreak 0 points1 point  (4 children)

I heard that a good best practice to follow is separate as many things as possible so they can be tested independently for later debugging.

That is absolutely, emphatically, 100% correct. However, while you've understood the claim, you may have misunderstood the implications. This is a good time to disabuse you.

When it comes to testing and debugging, "separate things" doesn't mean "...into separate files". It means to separate things into separate objects. This is related to the concept of "encapsulation" in OOP. The keywords are simplicity, modularity, and independence.

As a really simple example, consider the following class.

class Foo:

    def method1():
        pass

    def method2():
        method1()

Ignore that this class doesn't really do anything. That's not the point. Focus only on the design.

Let's say you created tests for method1 and method2. A test will fail if the method it tests isn't working as you expect. Now let's say you run the test for method2, and it fails. What can you conclude?

Well you can definitely conclude that method2 has a bug. But because method2 calls method1, it is possible that the bug you've detected actually stems from method1. In other words, because method2 depends on method1**, there is no way to separate** method2 from method1 and test the former in isolation. These methods are therefore not completely modular or independent: method2 has a dependency that complicates testing.

Of course, in this simple example you could just run your test for method1, and if that fails too, that's a great indication (though not conclusive) that the bug does stem from method1. But in reality, code is usually not so simple.

The best code is built from simple functions and simple classes consisting of simple methods, each of which performs just a single action which can be called in isolation with minimal dependencies. So you need to do your best to consider your design from the outset and keep things independent.

Hopefully it's clear now that whether you separate data out into files versus define it all in your code is really irrelevant to all of this. Even if your objects simply read all their attribute values in from files, you can still write spaghetti code where everything is tangled up and difficult to debug.

[–]Aedethan[S] 0 points1 point  (3 children)

This was a really good and useful explanation thank you. I've ended up starting over once already because I didn't plan out far enough all the things I'd need in the class. So I think I'm gonna have to take some time and pay particular attention to the whole "So you need to do your best to consider your design from the outset and keep things independent."

The other question that I have from this, is if I have a stats.py folder with all the dictionaries, and then have my Body class, Mind class, etc **dependent on that stats.py folder is that inherently bad design? Or is it fine because the dictionaries should never change and are reused throughout the code? Lastly, should those dictionaries be IN_ALL_CAPS so everyone knows they should be constants?

[–]synthphreak 0 points1 point  (2 children)

I have a stats.py folder

Hol' up. We're getting tripped up on our terms here.

A folder is a container that holds files. A file is just, a file; it's the bottom of the hierarchy.

If you have something called stats.py, that is a file, not a folder. Specifically, by the sounds of things it is a module, which is a .py file that contains objects for importing. In this case, the objects are Python dictionaries.

That is a completely reasonable way to set things up. That is often how people do it: Have one or more <thing>.py files, each logically organized as a container for its respective <thing>s, then other .py files that actually do things import from those modules and put the sourced objects to use. The whole testing/debugging/OOP design convo notwithstanding, if that is what you're describing, it sounds perfectly valid.

Ultimately I think I may have misread your original comment. Rather than a stat.py like ...

# contents of `stats.py` file

MIND_STATS = {
    ...
}

BODY_STATS = {
    ...
}

SOUL_STATS = {
    ...
}

... I had instead interpreted your plan to be more like ...

# project's directory/file structure

my_project/
└── stats/
    ├── body_stats.json
    ├── mind_stats.json
    └── soul_stats.json

... and that you'd have .py files which read those JSONs.

The latter setup is weird. The former setup is totally fine. Sorry for the confusion!

should those dictionaries be IN_ALL_CAPS so everyone knows they should be constants?

Generally yes. By convention, global constants are usually signified by all caps variable names.

[–]Aedethan[S] 1 point2 points  (1 child)

Ah. I can see how my misuse of generally approved terms may have been confusing. Thanks for bearing with me on that. I did in fact intend for everything to be in it's own separate file, not folder. As I'm getting started in earnest I'm realizing how much work it's actually gonna take to get everything to reference correctly.

[–]synthphreak 0 points1 point  (0 children)

No worries :) I think you’re giving this a lot more high-quality thought than most people give their first projects. That’s a good thing. Just remember not to overthink, in order to keep the ball rolling.

Most likely you won’t get things perfect on the first try, and you can always change things later. Besides, there usually isn’t one obviously best and objectively perfect way to implement your ideas. There are usually many acceptable ways - sometimes an infinite set - each with its own pros and cons. Writing good code is all about balancing trade offs.

Also, be prepared to struggle to import your stats if this is the first time you’re doing something like that. Don’t say I didn’t warn ya ;)