Forum Archive

Text input in a based Game

adrius42

I have attempted to search this forum via Google, to answer the question.
No joy apart from some old posts stating that it is not possible.

Has anyone come up with a method for resolving this?

I can call a menu but have not figured out how to get text input.....

Ideas anyone?

cvp

@adrius42 see here and here

cvp

@adrius42 just to show it, little modification of Examples/Animation/Magic Text.py
Tap on top of screen, it will show a popover ui.TextView where you can change the text.
If you tap lower and move your finger, you get the standard process of the script.

# coding: utf-8

'''
Draw lines on the screen to reveal the 'Zen of Python' -- or replace it with your own text (by changing the MESSAGE string).
'''

from scene import *
import random
import math
import ui
from colorsys import hsv_to_rgb
A = Action

FONT_NAME = 'Ubuntu Mono'
if min(ui.get_screen_size()) > 750:
    FONT_SIZE = 60
else:
    FONT_SIZE = 30
SPACING = FONT_SIZE * 0.45

MESSAGE = '''The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
'''

class MyScene (Scene):
    def setup(self):
        self.hue = 0.0
        self.prev_touch = None
        self.letter_index = 0
        self.background_color = '#262b30'
        self.instructions = LabelNode('Tap at top to change text or \nDraw with one finger.', ('HelveticaNeue-Light', 24), position=self.size/2, parent=self)

    def did_change_size(self):
        if self.instructions:
            self.instructions.position = self.size/2

    def textview_did_end_editing(self, textview):
        global MESSAGE
        MESSAGE = textview.text
        textview.end_editing()
        textview.close()
        return True

    def touch_began(self, touch):
        if touch.location[1] > (ui.get_screen_size()[1]-50):
            tv = ui.TextView()
            tv.font = ('Menlo',15)
            tv.frame = (0,0,400,500)
            tv.delegate = self
            tv.text = MESSAGE
            tv.begin_editing()
            tv.present('popover', popover_location=(touch.location[0], ui.get_screen_size()[1]-touch.location[1]), hide_title_bar=True)
            return
        if self.instructions:
            self.instructions.run_action(Action.fade_to(0, 1))
            self.instructions = None
        self.prev_touch = touch.location

    def touch_moved(self, touch):
        d = touch.location - self.prev_touch
        if abs(d) < SPACING:
            return
        letter_pos = self.prev_touch + 0.5 * d
        self.prev_touch = touch.location
        letter = MESSAGE[self.letter_index]
        self.letter_index += 1
        self.letter_index %= len(MESSAGE)
        if not letter.strip():
            return
        a = -math.atan2(*d) + math.pi/2
        font = (FONT_NAME, FONT_SIZE)
        color = hsv_to_rgb(self.hue, 0.65, 1)
        label = LabelNode(letter, font=font, position=touch.location, color=color)
        label.rotation = a
        self.hue += 0.03
        label.run_action(A.sequence(
            A.move_to(letter_pos.x, letter_pos.y, 1.2, TIMING_ELASTIC_OUT),
            A.wait(3),
            A.scale_to(0, 0.25),
            A.remove()))
        self.add_child(label)
        for i in range(5):
            p = SpriteNode('shp:Spark', position=letter_pos, color=color)
            p.blend_mode = BLEND_ADD
            r = max(FONT_SIZE, 50)
            dx, dy = random.uniform(-r, r), random.uniform(-r, r)
            p.run_action(A.sequence(
                A.group(
                    A.scale_to(0),
                    A.move_by(dx, dy, 0.5, TIMING_EASE_OUT_2)),
                A.remove()))
            self.add_child(p)

if __name__ == '__main__':
    run(MyScene(), multi_touch=False)

mikael

@adrius42, if you want your text input to be a part of the scene and not a ’popover’, there is this in the docs:

”You can also use this approach to add traditional UI elements (e.g. text fields) to your game. For this purpose, you don’t have to create a SceneView – you can simply use the view that was created automatically, using your Scene‘s view attribute (this will only work if a scene is already being presented of course).”

mikael

@cvp, I see many of your excellent answers utilize the ’popover’ present option. Please note that this only works on the iPad.

cvp

@mikael You are right, as I have an iPad. Here, it is only a quick sample but in my other last scripts about ObjectveC ViewControllers, you can use them as popover and sheet.

cvp

@mikael In my post just above my little sample, I pointed to a @ccc example with these features

enceladus

You could also use dialogs.

    def touch_began(self, touch):
        if touch.location[1] > (ui.get_screen_size()[1]-50):
            global MESSAGE
            MESSAGE = dialogs.text_dialog('enter text', text='')
            self.letter_index = 0
            return
        if self.instructions:
            self.instructions.run_action(Action.fade_to(0, 1))
            self.instructions = None
        self.prev_touch = touch.location
FarmerPaco

I might be late to this conversation but I am using Scene to build a visual Zork, and I find that ui.textfield works perfect for input.

```
def player_input(self):

    def command_given(sender):
        self.command = com_input.text
        self.player_command()

    com_input = ui.TextField()
    com_input.name = 'What next?'
    com_input.autocapitalization_type = False
    com_input.background_color = 'lightblue'
    com_input.frame = (0, 0, 500, 50)
    com_input.present('popover', popover_location = (5, 685))
    com_input.clear_button_mode = 'always'
    com_input.action = command_given

def player_command(self):

    if self.command in ['north', 'south', 'east', 'west']:
        self.current_room = self.current_room.move(self.command)
    self.player_roominfo()  ```
FarmerPaco

Here is a sample of using ui.textfield for input in scene

Here is a pic of textfield receiving input in Scene.