[SUGGESTION] Classes as Object-Oriented Data/Storage

Discussion and feedback on Construct 2

Post » Sat Sep 27, 2014 8:27 pm

Warning: There's a bit of a long read ahead. But try and get through it, I put a ton of thought into this and I think it's worth your time :)

Construct 2 plays a very difficult game - a great balancing act of making an engine simple enough for non-programmers to use while maintaining the
flexibility and complexity required by advanced developers. And it does this brilliantly - mostly.

One feature, which is commonplace in just about every high level OOP language, seems to be neglected and forgotten about, even though it is
crucial to almost every modern day application.

I am talking, of course, about Classes. You know, those customizable objects with their own properties and variables.

"So you mean Sprites?" I can hear you asking.

Well, sort of.

While Sprites do have the ability to store information in themselves through Instance Variables, I feel that they are severly limited. First of all, using a
Sprite to store data just seems strange. I mean, sure, I can spawn new ones off the layout with their own variable values, but that seems way too
much like a workaround rather than a feature. And I'm fairly certain that the process of creating a sprite, albeit offscreen, is far more resource
intensive than manipulating much simpler data.

Second of all, there are only three (3!!!) data types available for instance variables - Number, Boolean, and Text. While this may work for simple
things, it is borderline unusable for more complex problems.

Let's take an example:

Let's say I'm making a pizzeria simulation game. A customer calls and places an order, and I need to fill out the order properly, through mini games
and memorization. Stuff like remembering toppings, customer details, slice cutting, seasoning, and the works. Sounds simple, right? But let's look at
the classes and properites needed:

Code: Select all
Customer - First Name(text), Last Name(text), Phone Number(number), Address(text), Slices Ordered(???)


If I were to use a conventional programming language, this would be very simple. I would simply create a Slice class that looks like this:

Code: Select all
Slice - Toppings(text array)


And then make the Slices Ordered property be an array of Slice objects.

Code: Select all
Customer - First Name(text), Last Name(text), Phone Number(number), Address(text), Slices Ordered(Slice array)


While simple through conventional programming, this is ridiculously difficult in Construct 2.

Sprites cannot have arrays, dictionaries, or other Sprites (or even anything remotely object related) as an Instance Variable. So instead, I'd have to
resort to using confusing, sideways solutions like using 3D global arrays (for something so obviously non global!) as subsitutes and just parsing
through row, column, and depth for each property, value (which can be an array!), and customer respectivly. And parsing that is hell. And should be
entirely unnecessary.

I hope you see my problem by now.

"So, what's your solution?" I can hear you asking.

Well, it's definitely not going to be easy to implement, but I definitely think it's possible, and necessary. Please note that this is just how I envision
this, and is definitely not the only way to do this.

So you double click the screen, and add a "Class" object. It's added to your object bar, but not shown on screen, like an array or dictionary. When
selected, it shows the "Object type properties", "Container", and an "Variables" bar (just to avoid confusion with Instance Variables. You'll see why in
a second). The only thing that is different here is that the Variables bar (which has an "Add/Edit" option, like we're used to) when clicked, and after
pressing the add button, the available types shown are: Number, Boolean, Text, Array, Dictionary, and any other classes that you have created
on this layout
. If the Array or Dictionary options are selected, the Initial Value field expands to contain all of an Array's or Dictionary's starting
Properties panel (in the case of an array - width, height, and depth), and in the case of a Class, all non-complex variables (number, text, boolean)
are shown, and then, in a recursive hierarchical fashion, each complex object shows its information until the lowest, only non-complex variable level is
reached. Just visualize it like nested dropdown lists, much like http://orteil.dashnet.org/nested.

So you've created your class! Whoo! But be patient - it's not on the layout yet. You've just built the abstract of it. Let's jump to the event sheet and
get this thing in our game.

Let's have a look at it's actions. Click "Add Action", and each Class object that you've created appears there, like any other object does. Each class
has the actions "Initialize", "Destroy", and "Set Variable" (there could definetly be more, these are just the essentials). "Initialize" opens up a menu
box identical to what is shown when setting the Class's default variable values, except at the top it has a "Tag" or "Name" option, much like audio
files. This is what will be used whenever you need to access this specific instance of the class. "Destroy" takes a name and destorys the instance
related to it. "Set Variable" allows you to set the value of one of the variables in this instance.

So if I want to compare the value of "Name" inside of the instance "customer1" of the Class "Customer" with the string "Bob", I would access it by
typing something along the lines of

Code: Select all
Customer.getInstance("customer1").getValue("Name")


Or if I wanted to get his street number, which is stored in another class called "Address", I would access it by typing

Code: Select all
Customer.getInstance("customer1").getClass("Address").getValue("Street Number")


Or if I wanted to access an Array of something stored in the customer

Code: Select all
Customer.getInstance("customer1").getValue("SomeArray").At(1,1,1)


This may seem a bit too programmer-y, but again, this is just the way that I see things, and is completely up to anyone's interpretation.

Condition-wise, there shouldn't be too much, just maybe a "Is Initialized" option or something along those lines.

And that's basically it. So while this may be difficult to implement, it definitely is possible. Thanks for taking your time to read this, and if you have
any questions don't hesitate to respond here or shoot me a tweet @bowiz2. I tried to make this as understandable as possible, but I may have failed
miserably - so let me know!

Have a great day!
B
40
S
9
G
6
Posts: 61
Reputation: 6,001

Post » Sat Sep 27, 2014 11:43 pm

Hey man. I have read the entire post. Don't have time for an in depth reply as I'm mobile. Have you done a search on "oop" as this has been raised quite a few times (including by me). You're right about c2 walking that fine line. I'm an oo guy from way back don't get me wrong. I think just having a simple "data" object (POD) would be great, to aggregate values and combine those objects into compound objects. Arrays of these would be great too. I think I'm agreeing with the spirit of your post, but keeping it simple. I don't think that would be difficult to implement, but who knows. I don't like the accessing of fields by string name though.
B
24
S
9
G
4
Posts: 1,646
Reputation: 6,596

Post » Sun Sep 28, 2014 12:04 am

"Sprites cannot have arrays, dictionaries, or other Sprites (or even anything remotely object related) as an Instance Variable."

See that part that says container?

Also you're not limited to one instance of any data object, and you can reference them using the index array(0), array(1) etc.
Image ImageImage
B
170
S
50
G
179
Posts: 8,378
Reputation: 113,425

Post » Tue Sep 30, 2014 4:00 pm

Overall I agree: handling complex data structures and algorithms is difficult within the current event system, and the spirit of this suggestion is to resolve that. I'm not sure I agree with the specifics, but I agree that there is a weakness and that something along the lines of what is suggested would help. However such changes are deep and far-reaching and would require quite some rearchitecting. I don't think we could start addressing this within a C2 time-frame (more like C3, whenever that may be).

I do however have some random points to add to what you've said which might help you realise the situation as it is right now is perhaps not quite so bad as you think:

bowiz2 wrote:And I'm fairly certain that the process of creating a sprite, albeit offscreen, is far more resource intensive than manipulating much simpler data.

Not really - sprites are actually very well optimised. If it has no animations, it sits on an invisible layer, and you don't make any collision checks, then IIRC it has no performance overhead from simply existing. This means it's actually a pretty reasonable idea to have some global sprites as a sort of namespaced global variable solution. So you can for example have some variables with names like "Stats.Accuracy", "Inventory.ItemCount", etc.

Sprites cannot have arrays, dictionaries, or other Sprites (or even anything remotely object related) as an Instance Variable.

No, but an interesting feature of containers is that you can put an array or dictionary in a container with a sprite, and each instance of a sprite gets its own array/dictionary instance. The way picking works with containers also means once you pick one of those sprites with events, all actions/expressions to do with its contained arrays/dictionaries refer to its own objects only. You can add several arrays or dictionaries to a sprite in its container and have all sorts of per-instance advanced data structures for different purposes. While that's not using instance variables, it achieves the same end, and hopefully is a good workaround.

Customer.getInstance("customer1").getValue("Name")

One of my concerns with expressions like this is performance. If "Customer.getInstance" returns an entire customer record with *all* their data, and then you discard it all and retrieve only the name, and then you do that a lot, then there's a lot of wasted effort going on. It's solvable with by-reference passing and so on, but it gets complicated if you want to start adding expressions that modify the result, such as slicing arrays and such.

Other options could include:
- involve this in a new modularity system somehow
- better ways to integrate JS code (which is quite an extreme way to solve the problem I guess)
Scirra Founder
B
399
S
236
G
89
Posts: 24,519
Reputation: 195,361

Post » Tue Sep 30, 2014 4:54 pm

It's coo, to chain the output of expressions. And I agree that put an algorithm on event sheet is (very) difficult, I usually put it into plugin/behavior.
In my point of view, reuse-able (by plugins) is more important than easy to program in event sheet. Encapsulation is also a part of OOP, that's way I LOVE C2. Don't miss the event-plugin system in C3.
Of course, chaining the output of expressions will be more better.
B
109
S
27
G
276
Posts: 4,479
Reputation: 154,418


Return to Construct 2 General

Who is online

Users browsing this forum: No registered users and 12 guests