Variable name / The separation of the namespace

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
DemiDem
Newbie
Posts: 4
Joined: Fri Jun 08, 2018 6:10 am
Contact:

Variable name / The separation of the namespace

#1 Post by DemiDem »

I have a location;
location have a sub_location;
sub_location have another sub_location;
etc...

In general, I need to find the acceptable way to name the variables.
Of course, I can named them like...

New_york_Manhattan_Fifth_avenue_Empire_state_building_103_floor_My_office_location

But I think it's the wrong way.
The separation of the namespace, I think, it's right way.
Because Renpy's projects has a common namespace I need to find a way separate it. (Or do something else)
Help me please with this problem.

P.S. Sorry for my English.

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Variable name / The separation of the namespace

#2 Post by kivik »

Can you tell us more about how you intend to use these variables / locations?

You've given quite a massive nested list of locations - I'd argue it's more detailed than a AAA game like Grand Theft Auto since even they don't populate every building with floors and rooms (far as I know, never really played it). Granted I know you wouldn't have every single street and building and floor and room, but the nesting of locations is quite deep.

That's why some insight into what you're doing, what kinda of scale (how many cities are there? how many towns? streets? buildings? floors? rooms? would be helpful to point you in the best direction.


On the one hand you can use a dictionary to manage the nesting, it doesn't make it any easier to read, but the information will be structured, and the information level can be abstracted.

E.g. if you're arrive in New York, you pass the New York dictionary to your functions, and that function only has to look at the town; then you pass it into another function that only needs to look at the streets > then the buildings etc. etc. So you don't have to write out the full variable names.


On the other hand you may want to use a linked list object to represent all locations, and give them a parent and child node. New York will have children Manhattan, Brooklyn, Queens etc. (I don't know my American cities), then Manhattan will have fifth avenue as a child, but New York as its parent > fifth avenue will have Manhattan as its parent and Empire State Building as a child etc.

Then you can mostly just past a single linked list object around, and determine how to go up one level (by looking at the parent), or what levels you can go down in (by looking at its children).


Again, it really depends on what exactly you're trying to do with your game.

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Variable name / The separation of the namespace

#3 Post by Remix »

As kivik says, most of your options are dependent on your use requirements and in general highly dependent upon your rigidity of naming protocol.

Personally I would create a folder hierarchy that reflects the locations and use a class to automatically explore that to dynamically build all the location objects and parent/sibling/child referencing.
That way you only have one object reference in the global namespace and a map of all paths to all other locations
e.g.
new_york/
new_york/manhattan/
new_york/manhattan/fifth_avenue/
new_york/manhattan/fifth_avenue/empire_state_building/
new_york/manhattan/fifth_avenue/empire_state_building/101_floor/
new_york/manhattan/fifth_avenue/empire_state_building/102_floor/
new_york/manhattan/fifth_avenue/empire_state_building/103_floor/
new_york/manhattan/fifth_avenue/empire_state_building/103_floor/my_office/
The object traverses the folders and creates locations based on folder names, linking each to its parent and children.

As your MC/player moves around he simply changes his 'current_location' to be the relevant object and expects that object to know all its data (e.g. bg images, events etc)
Frameworks & Scriptlets:

DemiDem
Newbie
Posts: 4
Joined: Fri Jun 08, 2018 6:10 am
Contact:

Re: Variable name / The separation of the namespace

#4 Post by DemiDem »

Remix wrote: Fri Jun 08, 2018 6:07 pm As kivik says, most of your options are dependent on your use requirements and in general highly dependent upon your rigidity of naming protocol.

Personally I would create a folder hierarchy that reflects the locations and use a class to automatically explore that to dynamically build all the location objects and parent/sibling/child referencing.
That way you only have one object reference in the global namespace and a map of all paths to all other locations
e.g.
new_york/
new_york/manhattan/
new_york/manhattan/fifth_avenue/
new_york/manhattan/fifth_avenue/empire_state_building/
new_york/manhattan/fifth_avenue/empire_state_building/101_floor/
new_york/manhattan/fifth_avenue/empire_state_building/102_floor/
new_york/manhattan/fifth_avenue/empire_state_building/103_floor/
new_york/manhattan/fifth_avenue/empire_state_building/103_floor/my_office/
The object traverses the folders and creates locations based on folder names, linking each to its parent and children.

As your MC/player moves around he simply changes his 'current_location' to be the relevant object and expects that object to know all its data (e.g. bg images, events etc)
Yes!
I created a folder hierarchy too previously. And now you give me idea to create a function that creates a location variable from its path.

Something like this:

new_york/manhattan/fifth_avenue/empire_state_building/103_floor/my_office/my_office.rpy

my_office.rpy

Code: Select all

init python:
	my_office_Location = Location(...)

	## created variable "new_york_manhattan_ (...) _my_office" and assigns Location(...)
	create_location_var_from_path(my_office_Location) 
and then I can access it from the same file

Code: Select all

init +1 python:
	## get variable "new_york_manhattan_ (...) _my_office"
	my_office_Location = get_location_var_from_path()
	
	## and now I can use "new_york_manhattan_ (...) _my_office" like "my_office_Location"
	my_office_Location.set_movements(...)
	my_office_Location.set_objects(...)
	## ...	
Thanks!

DemiDem
Newbie
Posts: 4
Joined: Fri Jun 08, 2018 6:10 am
Contact:

Re: Variable name / The separation of the namespace

#5 Post by DemiDem »

...but will it work after the build?

User avatar
xavimat
Eileen-Class Veteran
Posts: 1461
Joined: Sat Feb 25, 2012 8:45 pm
Completed: Yeshua, Jesus Life, Cops&Robbers
Projects: Fear&Love
Organization: Pilgrim Creations
Github: xavi-mat
itch: pilgrimcreations
Location: Spain
Discord: xavimat
Contact:

Re: Variable name / The separation of the namespace

#6 Post by xavimat »

DemiDem wrote: Sat Jun 09, 2018 5:21 am ...but will it work after the build?
Why do you need the name of the rpy file? You can have a label with every visitable room and jump to it with "jump expression" or call it "call expression". You can have also hundreds of empty rooms: renpy can check if a label does not exist and jump to a "generic" label: "Nothing interesting here".
https://renpy.org/doc/html/label.html#jump-statement
https://renpy.org/doc/html/label.html#renpy.has_label
Comunidad Ren'Py en español: ¡Únete a nuestro Discord!
Rhaier Kingdom A Ren'Py Multiplayer Adventure Visual Novel.
Cops&Robbers A two-player experiment | Fear&Love Why can't we say I love you?
Honest Critique (Avatar made with Chibi Maker by ~gen8)

DemiDem
Newbie
Posts: 4
Joined: Fri Jun 08, 2018 6:10 am
Contact:

Re: Variable name / The separation of the namespace

#7 Post by DemiDem »

xavimat wrote: Sat Jun 09, 2018 6:27 am
DemiDem wrote: Sat Jun 09, 2018 5:21 am ...but will it work after the build?
Why do you need the name of the rpy file? You can have a label with every visitable room and jump to it with "jump expression" or call it "call expression". You can have also hundreds of empty rooms: renpy can check if a label does not exist and jump to a "generic" label: "Nothing interesting here".
https://renpy.org/doc/html/label.html#jump-statement
https://renpy.org/doc/html/label.html#renpy.has_label
But I can have child_child... many child_locations in one parent_location (area) and this will be difficult to implement in renpy code. (I think so)
Also, as the game progresses, these locations can be removed (destroyed) or replaced. And I think use labels may be a not good idea in this case.
I don't know...

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Variable name / The separation of the namespace

#8 Post by Remix »

I was thinking something a lot more dynamic... basically let the code do the heavy lifting so you can just concentrate on writing labels etc and expect them to automatically patch into your framework

The following code snippet does most of that with a focus on looking expressly for files named 'enter.rpy'
For each one it finds it builds a chain of Location objects reaching from the global scope referenced one through every folder
It then reads that file and takes the first label name as a label_namespace from which we can then use local labels to govern game context within that location...

Code: Select all


# this will create our Locations object under this name
#
define LOCATIONS_REF_NAME = "locs"

# tell Ren'Py which folder to use as the top of the stack
# basically which folder inside /game/ to use as a starting point
#
define LOCATIONS_FOLDER = "locations"

define e = Character("Eileen")

init 1 python:

    class Location(object):

        def __init__(self, name=None, parent=None, abbr=None):
            self.parent = parent
            self.children = {}
            self.path = [ name.lower() ] if name else []
            self.files = []
            self.abbr = abbr

        def __setattr__(self, key, value):
            if key == 'abbr' and value and value not in self.path:
                value = value if isinstance(value, (list, tuple)) else [value]
                for v in [ v for v in value if v not in self.path ]:
                    self.path.append(v)
            elif key == 'file':
                if value not in self.files:
                    self.files.append( value )
            else:
                super(Location, self).__setattr__(key, value)

        def __getattr__(self, key):
            if '.' in key:
                name, rest = key.split('.', 1)
                if name in self.children:
                    return getattr(self.children[name], rest)
            super(Location, self).__getattr__(key)

        def add(self, **kwargs):
            name = kwargs.get('name', None)
            if name and not name in self.children:
                self.children[name] = Location( parent=self, **kwargs )

        def get_offspring(self):
            kids = self.children.values()
            for c in self.children.values():
                kids += c.get_offspring()
            return kids

        def get_path_components(self):
            p = []
            if self.parent:
                pcs = self.parent.get_path_components()
                for pc in pcs:
                    p.append(pc)
            if self.path:
                p.append(self.path)
            return p

        def find(self, tags=[]):
            if not tags:
                raise ValueError, "Cannot perform find on empty list"
            if isinstance(tags, basestring):
                tags = [tags]
            poss_objs = []
            for k in self.get_offspring():
                if all( [
                    tag in [ g for h in k.get_path_components() for g in h ]
                    for tag in tags
                    ] ):
                    poss_objs.append(k)
            return poss_objs

        @property
        def dot_name(self):
            return ".".join( [ LOCATIONS_REF_NAME ] 
                             + [ k[0] for k 
                                 in self.get_path_components() 
                                 if k[0] ] )

        @property
        def file_path(self):
            return "/".join( [ globals()['LOCATIONS_FOLDER'] ] 
                             + [ k[0] for k 
                                 in self.get_path_components() 
                                 if k[0] ] )

        @property
        def title(self):
            if not self.path:
                return "None"
            return " ".join( [
                k.capitalize() for k in self.path[0].split() ] )

        @property
        def enter(self):
            if not hasattr(self, 'label_namespace'):
                raise AttributeError, "Location object has no label_namespace"
            return "{}.enter".format( self.label_namespace )


    globals()[LOCATIONS_REF_NAME] = Location()


    def map_folders():

        top = globals()['LOCATIONS_FOLDER']
        if top[-1] != "/":
            top += "/" 

        for k in renpy.list_files():

            if k.startswith(top) and k.endswith('enter.rpy'):

                dirs, file = k[len(top):].rsplit('/',1)

                obj = globals()[LOCATIONS_REF_NAME]

                for subdir in dirs.split('/'):

                    if not subdir in obj.children:

                        obj.add( name=subdir )

                    obj = obj.children[subdir]

                obj.file = file

                with renpy.file(k) as f:

                    for line in f:

                        line = line.strip()

                        if line.startswith('label '):

                            obj.label_namespace = line[6:-1]

                            break


    map_folders()


screen location( loc=None ):
    frame:
        ymargin 4
        background Solid("#4576")
        vbox:
            text "Title: [loc.title!q]"
            text "DotName: [loc.dot_name!q]"
            text "FilePath: [loc.file_path!q]"
            $ children = ", ".join( 
                [ c.title for c in loc.children.values() ] ) or "None"
            text "Children: [children]"
            text "Files: [loc.files!q]"

screen show_locations():
    frame:
        background Solid("#3457")
        # padding 10
        viewport:
            scrollbars "vertical"
            vbox:
                text "Locations:"
                hbox:
                    spacing 6
                    box_wrap True
                    for loc in globals()[LOCATIONS_REF_NAME].get_offspring():
                        use location( loc )



label start:

    show screen show_locations

    e "Start"
    # we defined our LOCATIONS_REF_NAME as 'locs', so we can use that
    $ good_locs = [ k for k 
                    in locs.get_offspring() 
                    if hasattr(k, 'label_namespace') ]
    jump expression renpy.random.choice(good_locs).enter
    e "End"
Now we can write similar enter.rpy files for every location we want:

Code: Select all

label fgh6r6drt65dd65e6554546:
    ""

label .enter:
    "You are here"
    jump .event1 
    return

label .event1:
    "Though many files might have a label named .event1, this one is used as we are local"
    return
The first label dictates a label_namespace and must be different for each location
Other label names start with a dot/period to make them local (so we can lazily reuse names)

You will likely want a way to reference any Location from inside labels etc (for setting vars and stuff)... I will leave that up to you to explore
Frameworks & Scriptlets:

Post Reply

Who is online

Users browsing this forum: Google [Bot]