Pseudo-OOP with slices?

Ask and answer questions about making games and related topics. Unrelated topics go in that other forum.

Moderators: marionline, SDHawk

Post Reply
User avatar
Baconlabs
Liquid Metal Slime
Posts: 1067
Joined: Mon Nov 02, 2009 6:29 am
Location: Middlin, TN

Pseudo-OOP with slices?

Post by Baconlabs »

Has anyone here ever attempted object/class programming with slices in their OHR games?

I'm in the middle of making a custom battle engine that, so far, has only needed slices for sprites, boxes, and other visual elements. Some data - like Hero/Enemy stats - I've been pulling from the numbers I enter ahead of time in CUSTOM, and other data - like sprite indices and maximum stats for enemies - I've been keeping track of with global variables and assigning with plotscripts. But, as I try to do more and more with this system, I'm starting to wonder if I'm going about this in an inefficient way. There has to be a better method.

My theory is to use persistent, invisible slices that act as pseudo-objects for all battle units, both Heroes and Enemies, with slice children containing data for some of the elements you'd see in the default Hero data - base stats, max stats, current stats, sprite info, spell lists, equipped items, etc. - as well as new things that the default Hero data doesn't keep track of - custom status ailment flags, for example, or X&Y values (not for position on the screen, but position in a custom-made grid). Who knows what else I might need in the future.

Anyway, if anyone's done anything like this before, I'd like to know, and I'd like to ask for your advice, or perhaps a peek at your source code.
Last edited by Baconlabs on Thu Jul 12, 2018 10:05 pm, edited 1 time in total.
User avatar
kylekrack
Liquid Metal Slime
Posts: 1240
Joined: Mon Jun 16, 2014 8:58 am
Location: USA
Contact:

Post by kylekrack »

I'm working on it right now. I can get you an example script I used, but it might need some tweaking. It's brief, but uses slices to make objects with attributes using slice extra data and private methods using subscripts. Let me know if you have any questions. I can also show you my implementation of this template. I used it to make more detailed NPC definitions.

Here's the script. I can PM you the hss file as well, if you want.

Code: Select all

# Template for Object Oriented Programming in Hspeak
# by kylekrack

# These constants refer to attributes within an NPC object
# They are related to extra data slots
define constant, begin
    0,att:thing1
    1,att:thing2
    2,att:thing3
end

#EXAMPLE
# If you want to call an existing Object's method, you would call:
# obj(#, setAttribute, arg1)

# CONSTRUCTOR
#   Adds a child slice to a global parent that represents the new object.
#   A new object's id is determined by the order in which it was created. 
#   In other words, the id is the child number of the parent slice.
# Attributes:
# 
# More attributes can be added by adding arguments to this Constructor script
script, newObj, field1, field2, field3, begin
    variable(dad, sl, sli)
    # Parent slice of all objects
    # I recommend making a parent slice for all of your objects, rather than 
    # making them direct children of the script layer. This parent slice 
    # should be created elsewhere, like a newgame script
    # Change lookup code to appropriate parent slice on the script layer
    # NOTE: you must add the lookup code to your hsi file by defining it in 
    # the slice collection editor
    dad := lookupSlice(sli:dad, sl:scriptLayer)
    
    # Alternatively, you could create these object slices directly on the 
    # script layer and refer to them from there. 
    
    # Make the slice that represents the Object
    sl := createContainer(0,0)
    setParent(sl, dad)
    
    # May create sub-slices to sl here as well to fit more attributes
    
    # Set Base Attributes
    setSliceExtra(sl, att:thing1, field1)
    setSliceExtra(sl, att:thing2, field2)
    setSliceExtra(sl, att:thing3, field3)
    
    # Set Sub-Slice Attributes
    # sli := createContainer(0,0)
    # setParent(sli, sl)
    # setSliceExtra(sli, extra0, field4)
end

# obj method constants
# This is like calling object.method(args) in Java or some other language
# : The parallel is "obj(id, methodConstant, args...)" 
define constant, begin
    0,getAttribute
    1,setAttribute
end
# Call this to access or manipulate data for an Object
script, obj, id, func, arg1=0, arg2=0, arg3=0, begin
    # Variables for slice handles (in hierarchy)
    variable(dad, sl, sli)
    
    # Parent slice handle 
    # Change lookup code to appropriate parent slice on the script layer
    dad := lookupSlice(sli:dad, sl:scriptLayer)
    
    # Object slice handle
    sl := sliceChild(dad, id)
    if(not(sl)) then(exitReturning(-1)) # Check if slice is valid
    
    # SUBSCRIPT CALLS
    switch(func) do, begin
        # ACCESS METHODS
        case(getAttribute)      sub:getAttribute(arg1)
        # MANIPULATION METHODS : 1 LINE
        case(setAttribute)      sub:setAttribute(arg1,arg2)
        # INVALID CALL
        case(else)              exitReturning(-1)
    end

    # ACCESS METHODS
    subscript, sub:getAttribute, type, begin
        # Return extra data based on type constant
        exitReturning(getSliceExtra(sl, type))
    end

    # MANIPULATION METHODS
    subscript, sub:setAttribute, type, val, begin
        # Return extra data based on type constant
        exitReturning(setSliceExtra(sl, type, val))
    end
end
My pronouns are they/them
Ps. I love my wife
User avatar
Bob the Hamster
Lord of the Slimes
Posts: 7658
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

Yes! You can look at my scripts in Don't Eat Soap, Bell of Chaos, Paladin Traducer, and Vorpal Florist. I used a very similar method OO in all of them.

It works pretty well. You can even fake methods by storing script references with the @scripname feature and call them with wrappers that use "run script by id"
User avatar
Baconlabs
Liquid Metal Slime
Posts: 1067
Joined: Mon Nov 02, 2009 6:29 am
Location: Middlin, TN

Post by Baconlabs »

Ah, thanks! Quick question before I get too deep into this - you're using a lot of camel-case statements, like "lookupSlice" instead of "lookup slice". Does hspeak recognize that? Have we always been able to do that? If so, I had no idea! I'll get to messing with this over the next week and let you know how well it goes.

Also, thanks James, I've never tried anything like what you're describing; after flipping through a bit of the Bell of Chaos source, I think I get the gist of how "run script by id" is supposed to be used. I'll keep this in mind going forward.
User avatar
kylekrack
Liquid Metal Slime
Posts: 1240
Joined: Mon Jun 16, 2014 8:58 am
Location: USA
Contact:

Post by kylekrack »

Can run script by id work for subscripts in any way? I recall tmc saying they don't, but I can't remember. I'm trying to think of how that could make the scripts I wrote any more efficient, but I think I wrote my way into a corner in that regard :/
My pronouns are they/them
Ps. I love my wife
User avatar
Baconlabs
Liquid Metal Slime
Posts: 1067
Joined: Mon Nov 02, 2009 6:29 am
Location: Middlin, TN

Post by Baconlabs »

All righty, stop me if any of this sounds iffy. Using a "Unit" template, I'll be making parent slices for each unit in the game with lots of child slices attached to them storing info about this and that. All parents will be created during the new-game script, but some will have their children left blank.

Parents defined as "Heroes" will have info assigned to their children during a Joins-the-Party script; these parents will be used throughout the entire game and modified over time with various scripts handling things like equipment and skill sets. Parents defined as "Enemies" will be used as templates that are created during the New-Game script and never modified - rather, a small number of blank-slate "Enemy" parents will have info copied into them from the Enemy templates when a battle begins, and it's those parents that will be referenced and modified during battles. (There will never be more than 9 Heroes and 9 Enemies in any given battle.)

After a bit of brainstorming, I've determined that each of these "Unit" parents will be assigned about 100 child slices each. Over half of that comes from building 3 new "spell lists" with 20 slots apiece. A lot of those children are also dedicated to individual status ailment flags, since I want those to be able to stack. Did I get carried away with this? Do you guys think that'll make the game slow to a crawl? I hope not. I don't plan on having more than 18 of these units active in any given battle, if that makes any difference.
Last edited by Baconlabs on Fri Jul 13, 2018 6:46 am, edited 1 time in total.
User avatar
Bob the Hamster
Lord of the Slimes
Posts: 7658
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

I don't remember if you can get @ references to subscripts or not. Tmc would remember.

The lathe number of slices you describe does not sound like a problem, but if you do want to reduce the number of slices, remember that you can cram a lot of data into a single invisible slice. Three "extra" data slots, x, y, width, height, four padding values.
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

I don't remember if you can get @ references to subscripts or not.
You can't. (Because they can't run without the parent scripts. HSpeak would have to check that you don't use any non-local variables from the parent scripts.)

An extra 1800 slices should have virtually no effect, as long as they aren't visible.

Example of stuffing data into a slice: fake arrays
Last edited by TMC on Sat Jul 14, 2018 7:12 pm, edited 1 time in total.
Post Reply