Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
[SPACE ESCAPE]-Game example to help with Game dev
-
@Karina said:
@stephen Yes, I know, I copied it to my pythonista when you showed it. But there a lot of things, don't know from where to begin it. I just used to write more linear, so it's difficult for me to understand. But it goes slowly
I shortened my
ButtonNode
and removed rhe Event Manage. there is some short comments on this one too.. hopfully it will help you understand better?import scene class ButtonNode(scene.ShapeNode): def __init__(self, action, name=f'ButtonNode', bg_color='lightgray', accessoryColor='red', icon=None, accessory='emj:Exclamation_Mark_2', anchor_point=(0.5, 0.5), font_family='<system>', font_size=16, parent=None, position=(0, 0), size=(120, 45), corner_radius=8, border_size=20, borderColor='black', text='', text_color='black', enabled=True, *args, **kwargs): # these mainly for call to super() self.x, self.y = position self.w, self.h = size super().__init__( path=scene.ui.Path.rounded_rect( self.x, self.y, self.w, self.h, corner_radius), fill_color=bg_color, stroke_color=borderColor, shadow=None, parent=parent, *args, **kwargs) # Normal Properties for Instance() self.enabled=enabled self.button_action=action self.name=name self.position=position self.size=size self.anchor_point=anchor_point self.icon=self._init_textures(icon) # for border self.border_size=border_size self.borderColor=borderColor self.corner_radius=corner_radius # for accessory self.accessory=self._init_textures(accessory) self.showAccesory=False self.accessoryColor=accessoryColor # for Label self.text=text if text != '' else self.name self.text_color=text_color self.font_family=font_family self.font_size=font_size # Container to hold each component. # is just a dict version of self.children but specific. self.components=dict({ 'accessory':None, 'icon':None, 'label':None}) self._setup(self.icon, self.accessory, self.components) # Type Check to make sure img is a string or ui.Image def _init_textures(self, img): if type(img) == str or type(img) == scene.ui.Image: return scene.Texture(img) else: return None # setup our Components def _setup(self, i, a, c): if a != None: # small indicator image in top left corner # if its enabled it will disable and hide when pressed # intended for stuff like new item in inventory... c['accessory']=scene.SpriteNode( texture=a, size=(self.size[1]/4, self.size[1]/5*1.5), position=scene.Point(-self.size[0]/2+7, self.size[1]/2-10), parent=self, z_position=4, color=self.accessoryColor) if i != None: # button image c['icon']=scene.SpriteNode( texture=i, size=scene.Size(self.size[1]/2, self.size[1]/2), position=scene.Point(self.w/2 - self.size[1]/3 , 0), parent=self, z_position=9) if self.text: # button text.. c['label']=scene.LabelNode( text=self.text, font=(self.font_family, self.font_size), position=scene.Point(0 , 0), anchor_point=(0.5, 0.5), color=self.text_color, parent=self, z_position=10) # called when you tap the button def Button_Tapped(self): if self.components['accessory'].alpha > 0: self.components['accessory'].alpha = 0 if self.enabled: self.button_action(self) # custom action def my_button_action(sender): print(f'{sender.name}: {sender.text}..') class main(scene.Scene): def setup(self): self.buttons=list([]) self.background_color='lightgray' self.my_button=ButtonNode( text='My Button', parent=self, action=my_button_action, position=scene.Point(self.size[0]/2, self.size[1]/2+100)) self.buttons.append(self.my_button) def touch_began(self, touch): for btn in self.buttons: if self.point_from_scene(touch.location) in btn.frame: btn.Button_Tapped() scene.run(main())
-
ShapeNode is a subclass of SpriteNode!
Yeah, they say it in docs, I just forgot🤦♀️. Then it's more clever to make ShapeNode base class
-
lw=self.line_width=10
Here why you're lw and self.line_width? One is not enough? And it seems it should be self.path.line_width cause Path has that attr.
self.bg_texture=SpriteNode( texture=Texture('pzl:Blue8'), size=self.size-(lw, lw), parent=self)
You're trying make here the form of Blue8, but with rounded angles?
-
@stephen in built in examples sometimes there are with pyui files. Do you use them?
-
@Karina said:
lw=self.line_width=10
Here why you're lw and self.line_width? One is not enough? And it seems it should be self.path.line_width cause Path has that attr.
ShapeNode
has a few setting for path so that you dont need to set them for every path. when you pass a new path object to yourShapeNode
it doesva check on the follwing Properties and if the value is not None it applies this to your new Path object.with that said if you have say
ShapeNode().line_width
set to 3 and for just the next path object you want the width set to 6. you would need to setShapeNode().path
to the new path object and then setShapeNode().path.line_width = 6
otherwise yourShapeNode().line_width
will overide the path's predefined value. Only reason not to just changeShapeNode().line_width
before creating the path is in this example you want it to only change once and would hate to forget to change it back lol.ShapeNode Path Properties:
ShapeNode().line_width ShapeNode().fill_color ShapeNode().path ShapeNode().shadow ShapeNode().stroke_color
-
@Karina said:
Here why you're lw and self.line_width? One is not enough?
Yes one is more than enough. I do this at times to shorten line length
-
as for you question here i had zero issues with bg.line_width when i ran this setup method inside my Scene subclass. ill need to see how you cal calling your setup here
@stephen here's the full code though I've changed a little reading your advices
from scene import * import ui def sw(): return get_screen_size()[0] def sh(): return get_screen_size()[1] def bw(): return 150 def bh(): return 140 class ButtonNode(ShapeNode): def __init__(self, rect=(0, 0, 150, 75), corner_radius=7, *args, **kwargs): super().__init__(img, *args, **kwargs) x, y, width, height = rect def setup(self): bg = ui.Path.rounded_rect(0, 0, 200, 200, 8) bg.line_width = 7 self.bg = ShapeNode(bg, stroke_color='blue', parent=self) self.add_child(self.bg) def button_tapped(sender): print(sender.text) class Main(Scene): def setup(self): self.background_color = '#eaeaea' down = ButtonNode('iob:arrow_right_b_256', size=Size(bw(), bh()), line_width=7, position=Point(sw()-70, sh()/2)) down.make_button() self.add_child(down) run(Main(), LANDSCAPE)
-
Do you know how to make it in portrait orientation? No matter which attr I pass, it's still in landscape. Or that's just because of version,of my iPad?
-
@Karina said:
Do you know how to make it in portrait orientation? No matter which attr I pass, it's still in landscape. Or that's just because of version,of my iPad?
Heres the script back. i did a few corrections. you were ading the new code but not using it. lol but thats ok. this stuff can make you pull your hair out from time to time. Af for your error message for line_width, it's not part of the constructor parameters so this must be set after calling the super's Init. Interpreter didn't know the property existed yet. I'm assuming it has to do with execution inside ShapeNode itself.
Also you need to remove your fill color to see your texture. But we are getting there!
At the moment we can not control our Orientation on iPad. It has to do with ios13 and multi-tasking support for Pythonista. But a few of us are working on that
from scene import * import ui def sw(): return get_screen_size()[0] def sh(): return get_screen_size()[1] def bw(): return 150 def bh(): return 140 class ButtonNode(ShapeNode): def __init__(self, rect=(0, 0, 150, 75), corner_radius=8, bakground_color='lightgreen', line_width=0, *args, **kwargs): super().__init__(*args, **kwargs) self.tint = bakground_color x, y, width, height = rect self.position, self.size = get_screen_size()/2, (rect[2], rect[3]) # def setup(self): bg = ui.Path.rounded_rect(x, y, width, height, corner_radius) bg.line_width = line_width self.bg = ShapeNode(bg, stroke_color='blue', fill_color='clear',parent=self) # self.add_child(self.bg) def button_tapped(sender): print(sender.text) class Main(Scene): def setup(self): self.background_color = '#b7b7b7' down = ButtonNode( texture=Texture('iob:arrow_right_b_256'), size=Size(bw(), bh()), line_width=5, position=Point(sw()/2, sh()/2), parent=self) # self.add_child(down) run(Main(), LANDSCAPE)
-
@Karina said:
Do you know how to make it in portrait orientation? No matter which attr I pass, it's still in landscape. Or that's just because of version,of my iPad?
i made a note on last post but i wanted to add that it sounds like your orientation lock is on
-
@stephen Yes it was so. But when it's off, orientation changes when I tint. And I want it to be just portrait
-
@stephen I generally understood your code, but how do you count those positions, of icon, accessory, button? Cause size[1]/5*1.5 seems quite confusing
I changed a little your code, now the icon is music, and when you tap plays random sounds. But the button is in the corner, you even can't see it fully😓 -
@Karina said:
@stephen Yes it was so. But when it's off, orientation changes when I tint. And I want it to be just portrait
ah this currently an issue with ipad apps running support for multiscreen multitasking. and when you run your script in Pythonista yourvactually adding a model to the editors Main View and Pythonista supports IOS 13's multitasking. Right now there has been issues with XCode on the matter. Here in a couple hours I'm going to write an module to rotate your main view when the Device's window rotates to give a similar effect. Hopefully temporary but better than nothin lol me and a few others tried to fix it and a workaround seems to be needed. So hang in there we will get you fixed up
-
@Karina said:
@stephen I generally understood your code, but how do you count those positions, of icon, accessory, button? Cause size[1]/5*1.5 seems quite confusing
I changed a little your code, now the icon is music, and when you tap plays random sounds. But the button is in the corner, you even can't see it fully😓May I see the code please
-
@stephen said:
this stuff can make you pull your hair out from time to time.
What that means? I'm not native speaker if what🙃
You talk about args that I wrote but not used?
Multi tasking is thing that you can program on pythonista? -
import scene import sound import random sw = scene.get_screen_size()[0] sh = scene.get_screen_size()[1] music_sounds = ['piano:A3', 'piano:C3', 'piano:C4#', 'piano:D4', 'piano:E4', 'piano:F4', 'piano:G3#'] class ButtonNode(scene.ShapeNode): def __init__(self, action, name=f'ButtonNode', bg_color='lightgray', accessoryColor='red', icon='emj:Musical_Notes', accessory='emj:Exclamation_Mark_2', anchor_point=(0.5, 0.5), font_family='<system>', font_size=16, parent=None, position=(0, 0), size=(120, 45), corner_radius=8, border_size=20, borderColor='black', text='', text_color='black', enabled=True, *args, **kwargs): # these mainly for call to super() self.x, self.y = position self.w, self.h = size super().__init__( path=scene.ui.Path.rounded_rect( self.x, self.y, self.w, self.h, corner_radius), fill_color=bg_color, stroke_color=borderColor, shadow=None, parent=parent, *args, **kwargs) # Normal Properties for Instance() self.enabled=enabled self.button_action=action self.name=name self.position=position self.size=size self.anchor_point=anchor_point self.icon=self._init_textures(icon) # for border self.border_size=border_size self.borderColor=borderColor self.corner_radius=corner_radius # for accessory self.accessory=self._init_textures(accessory) self.showAccesory=False self.accessoryColor=accessoryColor # for Label self.text=text if text != '' else self.name self.text_color=text_color self.font_family=font_family self.font_size=font_size # Container to hold each component. # is just a dict version of self.children but specific. self.components=dict({ 'accessory':None, 'icon':None, 'label':None}) self._setup(self.icon, self.accessory, self.components) # Type Check to make sure img is a string or ui.Image def _init_textures(self, img): if type(img) == str or type(img) == scene.ui.Image: return scene.Texture(img) else: return None # setup our Components def _setup(self, i, a, c): if a != None: # small indicator image in top left corner # if its enabled it will disable and hide when pressed # intended for stuff like new item in inventory... c['accessory']=scene.SpriteNode( texture=a, size=(self.size[1]/4, self.size[1]/5*1.5), position=scene.Point(-self.size[0]/2+7, self.size[1]/2-10), parent=self, z_position=4, color=self.accessoryColor) if i != None: # button image c['icon']=scene.SpriteNode( texture=i, size=scene.Size(self.size[0], self.size[1]), position=scene.Point(self.w/2 - self.size[1]/3 , 0), parent=self, z_position=9) if self.text: # button text.. c['label']=scene.LabelNode( text=self.text, font=(self.font_family, self.font_size), position=scene.Point(0 , 0), anchor_point=(0.5, 0.5), color=self.text_color, parent=self, z_position=10) # called when you tap the button def Button_Tapped(self): if self.components['accessory'].alpha > 0: self.components['accessory'].alpha = 0 if self.enabled: self.button_action(self) # custom action def my_button_action(sender): sound.play_effect(random.choice(music_sounds)) class main(scene.Scene): def setup(self): self.buttons=list([]) self.background_color='lightgray' self.my_button=ButtonNode(size=scene.Size(100, 70), text=None, parent=self, action=my_button_action, position=scene.Point(sw/2, sh/2)) self.buttons.append(self.my_button) def touch_began(self, touch): for btn in self.buttons: if self.point_from_scene(touch.location) in btn.frame: btn.Button_Tapped() scene.run(main())
Now I found button pos, just need to fix sizes of button and music
-
@Karina said:
@stephen I generally understood your code, but how do you count those positions, of icon, accessory, button? Cause size[1]/5*1.5 seems quite confusing
I changed a little your code, now the icon is music, and when you tap plays random sounds. But the button is in the corner, you even can't see it fully😓ive been trying to get back in the habbit of basing node sizing and positioning on the parent size. best way i can explain this is im cutting the parent's height into 5 peices then setting my nodes
y
to1 and a half peices so if the height of the parent was 50 myy
would be 15| | X | | | |
i usually use percentages but buttons are pretty small generally and the icon is even smaller so i used Fifths instead
-
its looking really good! heres a few spots i changed:
adjusted size and position:
if i != None: # button image c['icon']=scene.SpriteNode( texture=i, size=scene.Size(self.size[1]/100*80, self.size[1]/100*80), #changed position=scene.Point(0, 0), #changed parent=self, anchor_point=(0.5, 0.5), z_position=9)
added check for
self.accessory
to fix excption if None:def Button_Tapped(self): if self.accessory: #changed if self.components['accessory'].alpha > 0: self.components['accessory'].alpha = 0 if self.enabled: self.button_action(self)
then added dditional button to close the loop.
-
@Karina said:
@stephen said:
this stuff can make you pull your hair out from time to time.
What that means? I'm not native speaker if what🙃
You talk about args that I wrote but not used?
Multi tasking is thing that you can program on pythonista?What that means? I'm not native speaker if what🙃
im mean programming, especially in the begining, can get overwhelming and frustrating.
You talk about args that I wrote but not used?
nothing wrong with preparation 😊
Multi tasking is thing that you can program on pythonista?
I'm referring to a Multitasking in IOS13 but yes Pythonista supports it
-
@stephen now I want a he notes to jump a little when you tap, but it doesn't move. Smth like that was in flappy alien
def pulsate(self): actions = [A.move_by(0, 10), ] icon_sprite = scene.SpriteNode(self.icon) icon_sprite.run_action(A.move_by(0, 50, scene.TIMING_LINEAR))