ags1
|
 |
«
Posted
2013-04-13 10:17:54 » |
|
I am toying with a game (or maybe just a simulator) that involves a lot of data. I need to define lots of characters, skills, creatures and so on. I suppose ideally I should use XML or JSON to store the data but I'm lazy so I am creating little subclasses like this:
public static class FightingBow extends Skill { private FightingBow() { name = this.getClass().getName(); experienceMultiplier = 2; skillCost = SkillCost.linear; lock = new BowTraining(); description = "General skill in using bows."; }
And I have one big class called Skills containing lots of the above inner class definitions.
So I am effectively turning Java into a data file format. Of course this does not lock me in to compiled code, down the road I can add a file reader to load the data from XML. And some regular expressions will convert my Java data file to XML for me - but I was wondering if this approach is in general evil for reasons I cannot see, or virtuous?
|
|
|
|
Mac70
|
 |
«
Reply #1 - Posted
2013-04-13 10:48:49 » |
|
If you want to make your game moddable then yes, this is evil. Otherwise, I would still use external files to store data like this - this does not have to be xml files, personally I use classic txt files formated like this: 1 2
| Key=Value Another_key=Another_value |
Such files are really, really easy to write, modify and read.
|
|
|
|
Danny02
|
 |
«
Reply #2 - Posted
2013-04-13 11:23:57 » |
|
instead of what you are doing use enums, they are the same thing you did by hand. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| enum Skill { FightingBow(2, SkillCost.linear, new BowTraining, "General skill in using bows."), FireMagic(1, linear, new HogwartsEducation(), "burn your enemies with fire balls!!")
Skills(int e, SkillCost c, Lock l, String d){ expMult = e; cost = c; lock = l; description = d; } final int expMult; final SkillCost cost; final Lock lock; final String description; }
...
Skill skill = Skill.FireMagic
println(skill.name()); |
If you want to make your game moddable then yes, this is evil. Otherwise, I would still use external files to store data like this - this does not have to be xml files, personally I use classic txt files formated like this: 1 2
| Key=Value Another_key=Another_value |
Such files are really, really easy to write, modify and read. I wouldn't create new file formats anymore, with libs like Jackson json serialisation is soo much easier. example: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Skill { String name, description; int expMult; }
... Skill value = mapper.readValue(new File("BowFighting.json"), Skill .class);
... BowFighting.json: { "name" : "BowFighting" "description" : "..." "expMult" : 2 } |
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ags1
|
 |
«
Reply #3 - Posted
2013-04-13 11:56:38 » |
|
I think my approach is not evil, after some consideration. I have plenty of experience with XML and JSON, so I will use those formats down the road (if I need to) but doing it this way means that differences between my data and my model are compile-time errors, not obscure run-time errors. Refactoring to 'proper' JSON or XML is trivial after all.
|
|
|
|
ReBirth
|
 |
«
Reply #4 - Posted
2013-04-13 12:01:32 » |
|
@Danny02 On enum use toString() instead name().
|
|
|
|
nsigma
|
 |
«
Reply #5 - Posted
2013-04-13 14:23:49 » |
|
How about something based on the builder pattern instead? This would lead to code like below, without lots of specific subclasses. Makes this potentially easier to customize or switch to an XML / JSON approach later, while keeping your code the same. 1 2 3 4 5 6 7
| Skill fightingBow = Skill.builder() .name("Fighting Bow") .experienceMultiplier(2) .skillCost(SkillCost.linear) .lock( new BowTraining() ) .description("General skill in using bows.") .build(); |
I really like the way they're doing this in JavaFX to provide a clean Java DSL that also translates easily to XML. PS. Yes, I think your code is evil! 
|
Praxis LIVE - hybrid visual IDE for (live) creative coding
|
|
|
ags1
|
 |
«
Reply #6 - Posted
2013-04-13 18:08:03 » |
|
...or just use a big fat constructor :-)
public static final Species HUMAN = new Species(70, 3, 60, null, null, "Human"); public static final Species HALFLING = new Species(111, 4, 40, null, null, "Halfling");
Much more compact. It's not self-documenting, but I can live with that.
|
|
|
|
Danny02
|
 |
«
Reply #7 - Posted
2013-04-13 18:46:19 » |
|
@Danny02 On enum use toString() instead name().
no name is just fine, as it does exactly what he wants to do @ags1 pls take a look at enums, as it is exactly what you try to emulate
|
|
|
|
Riven
|
 |
«
Reply #8 - Posted
2013-04-13 18:47:39 » |
|
@ags1: constructors and methods with more than ~3 parameters are... horrible, it makes each and every callsite a big mess.
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings!
|
|
|
Longor1996
|
 |
«
Reply #9 - Posted
2013-04-13 19:37:55 » |
|
Hi there.
How about Valve Key/Value Files? They are easy to read/write/handle.
- Longor1996
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ags1
|
 |
«
Reply #10 - Posted
2013-04-13 21:50:20 » |
|
@ags1: constructors and methods with more than ~3 parameters are... horrible, it makes each and every callsite a big mess.
Actually I agree with you, but building up a big file of constructor calls is not so bad - each call is the same and IntelliJ tells me what all the parameters mean. A more verbose format like XML or JSON will be clearer in the long run, and I can easily migrate to that later on. Once the data has a structure, changing to another structure is trivial. At work I am always fighting a battle against the monster constructors with a dozen arguments (half of which can be null of course) as I have to explain them to our customers.
|
|
|
|
HeroesGraveDev
|
 |
«
Reply #11 - Posted
2013-04-13 22:53:22 » |
|
Your options are:
1. Creating separate classes for each different type. 2. Big constructor. 3. Builder pattern. 4. External resources.
Use the builder pattern if you only need to change some of the data. (ie: lots of it is the same as default) Use External resources if you want modding compatibility/tweaking variable ingame. Use Big constructors if lots of data is different with every instance. Use Separate classes when you need to use methods too etc.
|
|
|
|
ReBirth
|
 |
«
Reply #12 - Posted
2013-04-14 02:43:08 » |
|
Once the data has a structure, changing to another structure is trivial.
NO
|
|
|
|
Roquen
|
 |
«
Reply #13 - Posted
2013-04-14 07:44:41 » |
|
The forgotten option: code is data.
|
|
|
|
nsigma
|
 |
«
Reply #14 - Posted
2013-04-14 10:24:07 » |
|
Use the builder pattern if you only need to change some of the data. (ie: lots of it is the same as default) ... Use Big constructors if lots of data is different with every instance.
Your argument would appear to be backwards!  Use the builder pattern if lots of data is different with every instance (particularly if that data needs to be known at construction time - eg. immutable state) Use Big constructors if little data has to be passed in at construction time (ie: lots of it is the same as default, there are few parameters, or you're happy with mutable state / setters) @ags1: constructors and methods with more than ~3 parameters are... horrible
evil? 
|
Praxis LIVE - hybrid visual IDE for (live) creative coding
|
|
|
ReBirth
|
 |
«
Reply #15 - Posted
2013-04-15 02:02:27 » |
|
Riven is right. More than 3 params is bad because Eclipse will auto-format your constructor first line into 2 lines. Horrible.
|
|
|
|
ra4king
|
 |
«
Reply #16 - Posted
2013-04-15 03:43:25 » |
|
Or turn off all line-wrapping like I did.
|
|
|
|
ReBirth
|
 |
«
Reply #17 - Posted
2013-04-15 03:53:25 » |
|
That's more horrible to read D:
|
|
|
|
HeroesGraveDev
|
 |
«
Reply #18 - Posted
2013-04-15 07:40:37 » |
|
To answer you question, no, it isn't too evil.
Compared to enterprise-y code this is a masterpiece.
|
|
|
|
ags1
|
 |
«
Reply #19 - Posted
2013-04-15 19:28:39 » |
|
To answer you question, no, it isn't too evil.
Compared to enterprise-y code this is a masterpiece.
Nah... I think my code is definitely evil. My new code structure of ItemContainer<? extends Item> is much more beautiful. When I start loading from files nothing will change for the rest of the app, just the way I build the instances. I'm not keen on enums (in this case) as they lock you into a closed list and you need to change to a normal class when you change to reading from a file.
|
|
|
|
Zhon
|
 |
«
Reply #20 - Posted
2013-04-15 20:02:08 » |
|
Or turn off all line-wrapping like I did.
How do you do that? 
|
|
|
|
ra4king
|
 |
«
Reply #21 - Posted
2013-04-16 04:27:22 » |
|
In Eclipse: Window -> Preferences -> Java -> Code Style -> Formatter -> Edit -> Line Wrapping. There, I set everything to "Do not wrap" and set other settings. You can also customize the formatter to however you like.To save, you have to change the name on the top. In IDEA: File -> Settings -> Code Style -> Java -> Wrapping and Braces. Again, play around 
|
|
|
|
princec
|
 |
«
Reply #22 - Posted
2013-04-16 07:45:31 » |
|
I like c'tors with lots of arguments  Winds Riven up no end. We work at different ends of the codebase, passing likes ships in the night  Cas 
|
|
|
|
|