Inheritence of Character and doubts about screen language

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
sqmath
Newbie
Posts: 18
Joined: Fri Jun 14, 2013 11:03 am
Contact:

Inheritence of Character and doubts about screen language

#1 Post by sqmath »

First, before anything else. Is Character a class?
I've been thinking of a special layout for my say screen and I think it would be far easier if I could inherit from Character. I'll explain myself.

The idea is to show two textboxes at the top and bottom of the screen. One belonging to the character in the left, one to the character in the right. I have no clue about how to show those two textboxes adapting the code from the default say screen.

The other part of the problem is how to show a Character image at the left and right positions of the screen AUTOMATICALLY. My idea is to implement a class Character2 which inherits from Character that includes some other atributes that manage current position, preferred position and so, with some functions too, so I can just type

a "how's it going?"
b "fine I guess"
c "are you two okay?"

and the program would place them in the left or right of the screen with a simple algorithm just looking at the attributes of the new class.

I know I could make it simpler, but if this could be made, writing would be far easier for my scriptwriter.

Thanks for your help,

sqmath

apricotorange
Veteran
Posts: 479
Joined: Tue Jun 05, 2012 2:01 am
Contact:

Re: Inheritence of Character and doubts about screen languag

#2 Post by apricotorange »

Character is actually a function which returns an object. But you can inherit from ADVCharacter, which is the actual class (although it isn't well documented... if you dig into the Ren'Py source code, NVLCharacter is a good example of what you can do). Or you can just write an independent class with a __call__ method; Ren'Py will treat anything it can call like a character.

sqmath
Newbie
Posts: 18
Joined: Fri Jun 14, 2013 11:03 am
Contact:

Re: Inheritence of Character and doubts about screen languag

#3 Post by sqmath »

Thanks, yesterday I arrived to the same conclusion. The problem is what you say, ADVCharacter isn't documented and I've been struggling with some problems.

My issues are at this step right now. I have my Ch object, inherited from ADVCharacter, and I want it to pass different window_ properties to the say screen, but I can't find the proper field inside ADVCharacter nor a setter method, so I've solved to create two separate Ch with different properties to manage that. Obviously, this is quite inneficient. Would you tell me how these fields are named, my problems would almost be solved.

Thanks anyway,
sqmath

sqmath
Newbie
Posts: 18
Joined: Fri Jun 14, 2013 11:03 am
Contact:

Re: Inheritence of Character and doubts about screen languag

#4 Post by sqmath »

Okey, found it. If anyone needs it, this is the solution.

ADVCharacter has fields show_args, cb_args, what_args, window_args and who_args, which are all DICTIONARIES. Its keys are the names of the property you want to change without its prefix. For example, if you want to change window_pos, you must code, being self the ADVCharacter,

self.window_args["pos"] = (0,0)

being (0,0) the value you want to assign to window_pos. The same with what_args and who_args (i don't know what show_args and cb_args are for)

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Inheritence of Character and doubts about screen languag

#5 Post by trooper6 »

Do you think you could post the code for the entire Character class you created? And then maybe some lines of it in action? I think it would be instructive and I'd learn some good stuff.
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

sqmath
Newbie
Posts: 18
Joined: Fri Jun 14, 2013 11:03 am
Contact:

Re: Inheritence of Character and doubts about screen languag

#6 Post by sqmath »

trooper6 wrote:Do you think you could post the code for the entire Character class you created? And then maybe some lines of it in action? I think it would be instructive and I'd learn some good stuff.
It's most possible I messed up a little with too many methods, but I feel comfortable with more functions than needed to code. So, excuse me if there's too much. Here's the code.

Note: Characters is just a storing class to save the needed variables. You only need to know about shownCharacters and lastSpeaker.
Note2: Images are not shown yet, but whenever there's a message down, there will be an image at the left side of the screen, and up->right.

Code: Select all

init python:
    
    #Stores all data relating to Characters
    class Characters(object):
        shownCharacters=[None, None]
        lastSpeaker = -1
        ch_list = []
        
        #Called automatically each time a Character is created
        @staticmethod
        def addCh(ch):
            Characters.ch_list.append(ch)
        
        #Called automatically each time a Character is deleted
        @staticmethod
        def delCh(ch):
            Characters.ch_list.remove(ch)

        @staticmethod
        def reset_data():
            for ch in Characters.ch_list:
                ch.reset()

    class Character(ADVCharacter):    
        def __init__(self, name, kind=adv, 
            preferredLocationLeft=False, 
            associatedDisplayable=None, **args):
            
            super(Character, self).__init__(name, **args)
            Characters.addCh(self)
            
            self.preferredLocation = int(not preferredLocationLeft)
            self.currentLocation = -1
            self.currentlyShown = False
            
            self.associatedDisplayable=associatedDisplayable
            
        #Returns 0, 1, indicating the position this character is meant to occupy
        def decide_location(self):
            if self.currentlyShown:
                return self.currentLocation
            elif not Characters.shownCharacters[self.preferredLocation]:
                #Empty position
                return self.preferredLocation
            else:
                if Characters.lastSpeaker==self.preferredLocation:
                    #Go to the opposite location
                    return (1-(self.preferredLocation*2-1))/2 #Converts 0->1 1->0
                else:
                    return self.preferredLocation
        
        #Converts 0-1 position (left-right) to True-False, True=left, False=right
        def is_left(self, position): 
            #0-left-False, 1-right-True
            return not position
            
        #Sets new values to the location parameters depending on which position it's using
        def set_location_parameters(self, location):
            if self.is_left(location):
                self.window_args["pos"]=(0.5,1.0)
                self.window_args["anchor"]=(0.5,1.0)
            else:
                self.window_args["pos"]=(0,0)
                self.window_args["anchor"]=(0,0)

        #Expels this Character from the position it's in
        def go_away(self):
            if Characters.shownCharacters[self.currentLocation]!=None and self.currentlyShown:
                self.currentlyShown = False
                Characters.shownCharacters[self.currentLocation] = None
                self.currentLocation = -1
                
        def go_away_with_transition(self, transition):
            self.go_away()
            #TODO: call a method to show how the character is going (use a transition)
            
        #Locates the Character in the most suitable position
        #according to the algorithm described in decide_location
        #Returns True if it wasn't already in the screen, False otherwise
        def come(self):
            if not (self.currentlyShown and Characters.shownCharacters[self.currentLocation] is self):
                self.currentlyShown = False
                location = self.decide_location()
                #Avoid the Null case and make it go away
                if Characters.shownCharacters[location]: Characters.shownCharacters[location].go_away() 
                
                Characters.shownCharacters[location] = self
                self.currentlyShown = True
                self.currentLocation = location
                self.set_location_parameters(location)
                
                return True
            return False
            
        #Locates the Character in the given position
        def come_at_location(self, location):
            self.go_away() #To avoid duplicates
            
            #Avoid the Null case
            if Characters.shownCharacters[location]: Characters.shownCharacters[location].go_away()
            
            Characters.shownCharacters[location] = self
            self.currentlyShown = True
            self.currentLocation = location
            self.set_location_parameters(location)
            
        #Method needed to use $ self("message") or self "message"
        def __call__(self, what, interact=True, **kwargs):
            self.come()
            Characters.lastSpeaker = self.currentLocation
            
            #We need to call the super class to avoid an endless loop
            super(Character, self).__call__(what, interact=interact, **kwargs)
            
        def __str__(self):
            data={'preferred location': self.preferredLocation,
                  'current location': self.currentLocation,
                  'currently shown': self.currentlyShown}
            return str(data)
                
        def __del__(self):
            Characters.delCh(self)
        
define e = Character("Eileen")
define o = Character("Oscar", preferredLocationLeft=True)
define a = Character("Alan", preferredLocationLeft=True)
define i = Character("Ian")

# The game starts here.
label start:
        
    o "bloblo"
    e "bleble"
    a "blabla"
    i "blibli"
    e "bleble"
    a "blabla"
    o "bloblo"
    
    return
You can copy this directly to the script. As you can see, you can define Characters just like before, except you now have a new parameter you may (or may not) want to use, preferredLocationLeft (bool), with use pretty straightforward. I leave you some code so you see how characters don't expel the last person talking, but still try to go to their preferred location.

Edit:
I've noticed some errors and I'm working on improving this. When I have it completed, I'll upload it here

User avatar
PyTom
Ren'Py Creator
Posts: 16088
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Inheritence of Character and doubts about screen languag

#7 Post by PyTom »

I'll note that the internal details of ADVCharacter are not documented, and may change at some point in the future.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Ocelot