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, this helped, esp that the sender is ui.Button. It is ui.Button or they just similar and somehow limited?
Not just any button. It's the same one you tapped on. It just like saying this:
my_button = ui.button(frame(0, 0, 150, 75), title='this is my button') sender = my_button
-
@Karina said:
It is ui.Button or they just similar and somehow limited?
i wanted to add that
sender
is just a positional argument. just likeself
andcls
. you can put any word you want. for example:def button_tapped(sender): and def button_tapped(button_that_was_tapped):
they both are the same outcome 😀
-
This post is deleted! -
In the
def Button_Tapped()
why do you set the conditionsif self.animated_icon and self.icon_animation
? Andif self.enabled
?
I didn't see where you fix them, there were just set in init. And the animation and sound both play when the button is tapped, so why don't put them in one condition? -
@Karina said:
In the def Button_Tapped() why do you set the conditions if self.animated_icon and self.icon_animation? And if self.enabled?
I didn't see where you fix them, there were just set in init. And the animation and sound both play when the button is tapped, so why don't put them in one condition?What do you mean by
fix them
?
# called when you tap the button def Button_Tapped(self): if self.components['icon']: if self.animated_icon and self.icon_animation: self.components['icon'].run_action(self.icon_animation()) if self.components['accessory']: if self.components['accessory'].alpha > 0: self.components['accessory'].alpha = 0 if self.enabled: self.button_action(self)
i see here i could of done this much better. but for each component we do a null check then if not
None
then run codes for needs.As for
icon
i have separate properties like this so i can store and hold an Action Object fromicon_animation
while being able to use theBoolean
animated_icon
to enable/disable animation. Otherwise i would have to seticon_animation
toNone
to disable and create a new one to Enable again. my goal withUIButton
is to have it so there is very little need to change or create anything once Developer creates thier button.note: The check on if there is a value for
icon_animation
is to avoid an excepton if there isn't one.For the improvment lets move the enabled check one level above everything else so we skip all the animation stuff if its not enabled:
# called when you tap the button def Button_Tapped(self): if self.enabled: if self.components['icon']: if self.animated_icon and self.icon_animation: self.components['icon'].run_action(self.icon_animation()) if self.components['accessory']: if self.components['accessory'].alpha > 0: self.components['accessory'].alpha = 0 if self.button_action: self.button_action(self)
-
What do you mean by fix them?
I mean that you set them once and didn't change. But your explanations helped though you didn't understood my question😄
Also it looks strange to me that you pass icon_animation as variable and then use it as a method -
I think I'll use all the animations, just instead of spin I tried to do jump
def Animation_Jump(duration=1.5): action_list=[] action_list.append( scene.Action.sequence( scene.Action.move_by(0, 20, duration/20), scene.Action.move_to(sw/6*5, sh/2, duration/20)))
The icon just disappears if use move_to, and move_by - if tap to often on the button, icon gets out from the frame (why this happens I understand). And when I check by print(self.my_button.position) it prints the right pos
-
@Karina said:
Also it looks strange to me that you pass icon_animation as variable and then use it as a method
hey sorry for the delay..
bestway to explain this is that functions, methods, classes and variables are objects. But not all are Callable i.e. Function and Method. a class can be a callable also if you Define the
__call__
magic method.what im doing with
icon_animation
is im creating a reference to the function and then when i need to call the function i use()
with any paraniter arguments thats needed.example:
def func(arg1, arg2): print(f'{arg1} and {arg2}') func_ref = func if __name__=='__main__': func_ref("foo", "bar")
-
@Karina said:
I think I'll use all the animations, just instead of spin I tried to do jump
def Animation_Jump(duration=1.5): action_list=[] action_list.append( scene.Action.sequence( scene.Action.move_by(0, 20, duration/20), scene.Action.move_to(sw/6*5, sh/2, duration/20)))
The icon just disappears if use move_to, and move_by - if tap to often on the button, icon gets out from the frame (why this happens I understand). And when I check by print(self.my_button.position) it prints the right pos
everything is great here but one small ... detail..
scene.Action.move_by(0, 20, duration/20)
is perfectly fine, your saying to move the node+20pts
on they
axis.scene.Action.move_to(sw/6*5, sh/2, duration/20)
Here is the problem.. lets say Originally your node is at(0, 0)
after first Action, your Node is now at(0, 20)
.. when you run this Action, you move the Node to 5/6 the screen width and 1/2 screen height. so if screen size is 600X800 you move the Node to(500, 400)
Animation Position Steps:
- (0, 0)
- (0, 20)
- (500, 400)
heres a fix:
scene.Action.move_by(0, 20, duration/20), scene.Action.move_by(0, -20, duration/20)
-
@stephen no problem, anyway thank you☺️
-
def Button_Tapped(self): if self.components['icon']: if self.animated_icon and self.icon_animation: self.components['icon'].run_action(self.icon_animation()) if self.components['accessory']: if self.components['accessory'].alpha > 0: self.components['accessory'].alpha = 0 if self.enabled: self.button_action(self)
It wasn't a good idea to put self.enabled in the beginning cause then the action didn't work - the button quit not working, sounds not playing
But I don't understand for what is it. You set it once and don't change -
I thought nodes measure their position in the parent's coordinate system
scene.Action.move_by(0, 20, duration/20), scene.Action.move_by(0, -20, duration/20)
I did it in the beginning, but if you tap to often, notes begin to exit the frame, because don't finish the last action
-
@Karina said:
@stephen no problem, anyway thank you☺️
not a problem, im just glad i can help 😊
@Karina said:
I thought nodes measure their position in the parent's coordinate system
yes they do but when you use
sw
you are getting the screen width not the width of the parent.you could of usedNode.parent.size[0]
to get the local width.@Karina said:
def Button_Tapped(self): if self.components['icon']: if self.animated_icon and self.icon_animation: self.components['icon'].run_action(self.icon_animation()) if self.components['accessory']: if self.components['accessory'].alpha > 0: self.components['accessory'].alpha = 0 if self.enabled: self.button_action(self)
It wasn't a good idea to put self.enabled in the beginning cause then the action didn't work - the button quit not working, sounds not playing
But I don't understand for what is it. You set it once and don't changeTry replacing the methods with this..
# called when you tap the button def Button_Tapped(self): if self.enabled: if self.components['icon']: if self.animated_icon and self.icon_animation: self.components['icon'].run_action(self.icon_animation()) if self.components['accessory']: if self.components['accessory'].alpha > 0: self.components['accessory'].alpha = 0 self.button_action(self)
i think because our Animation function doesnt return a value when not called using (). just a guess. lol
-
@stephen I thought super() is responsible for frame only, but I occasionally deleted it, and got empty screen. So what super() does?
P S I fixed that, now it's nearly how I want it to be -
I want to add some playing instruments and allow multi touch. But there's not many embedded pictures in pythonista, so I'll need somehow to work with files. In images I already did it, uploaded drums pict, only left with sounds
-
Now it's like that
import scene import sound import random import objc_util sw = scene.get_screen_size()[0] sh = scene.get_screen_size()[1] piano_sounds = ['piano:A3', 'piano:C3', 'piano:C4#', 'piano:D4', 'piano:E4', 'piano:F4', 'piano:G3#'] guitar_sounds = ['8ve:8ve-beep-warmguitar'] drum_sounds = ['drums:Drums_01', 'drums:Drums_04', 'drums:Drums_07', 'drums:Drums_10', 'drums:Drums_13', 'drums:Drums_16'] class ButtonNode(scene.ShapeNode): def __init__(self, action, icon, text_color, sounds, corner_radius=8, border_size=20, text='', name=f'ButtonNode', bg_color='lightgrey', anchor_point=(0.5, 0.5), borderColor=None, parent=None, position=(0, 0), size=(120, 45), enabled=True, animated_icon=False, icon_animation=None, *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.sounds=sounds self.enabled=enabled self.button_action=action self.name=name self.position=position self.size=size self.anchor_point=anchor_point # for border self.border_size=border_size self.borderColor=bg_color self.corner_radius=corner_radius # for icon self.icon_animation=icon_animation self.animated_icon=animated_icon self.icon=self._init_textures(icon) # for Label self.text=text self.text_color=text_color # Container to hold each component. # is just a dict version of self.children but specific. self.components=dict({ 'icon':None, 'label':None}) self._setup(self.icon, 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, c): if i != None: # button image c['icon']=scene.SpriteNode( texture=i, size=scene.Size(self.size[1]/100*80, self.size[1]/100*80), position=scene.Point(0, 0), parent=self, anchor_point=(0.5, 0.5), z_position=9) if self.text: # button text.. c['label']=scene.LabelNode( text=self.text, 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['icon']: if self.animated_icon and self.icon_animation: self.components['icon'].run_action(self.icon_animation()) if self.enabled: self.button_action(self) # custom action def my_button_action(sender): random_tone=random.choice(piano_sounds) play = random.choice(sender.sounds) sound.play_effect(play) return def Animation_Shake(duration=1.5): action_list=[] action_list.append( scene.Action.rotate_to(0.25, duration/10/2)) action_list.append( scene.Action.sequence( scene.Action.rotate_to(-0.5, duration/50), scene.Action.rotate_to(0.5, duration/50))) action_list.append( scene.Action.group( scene.Action.scale_to(1.0, duration/10/2), scene.Action.rotate_to(0.0, duration/10/2))) return scene.Action.sequence(action_list) def Animation_Pulse(duration=1.5): action_list=[] action_list.append( scene.Action.sequence( scene.Action.scale_to(1.2, duration/10/2), scene.Action.scale_to(0.5, duration/10/2))) action_list.append( scene.Action.scale_to(1.2, duration/50)) action_list.append( scene.Action.group( scene.Action.scale_to(1.0, duration/10/2))) return scene.Action.sequence(action_list) def Animation_Jump(duration=1.5): action_list=[] action_list.append( scene.Action.sequence( scene.Action.move_by(0, 20, duration/20), scene.Action.move_to(0, 0, duration/20))) return scene.Action.sequence(action_list) class main(scene.Scene): def setup(self): self.buttons=list([]) self.background_color='lightgray' self.guitar=ButtonNode(size=scene.Size(160, 112), icon='emj:Guitar', text=None, text_color=self.background_color, parent=self, action=my_button_action, sounds=guitar_sounds, position=scene.Point(sw/6*1.5, sh/3), animated_icon=True, icon_animation=Animation_Shake) self.buttons.append(self.guitar) self.my_button_pulse=ButtonNode(size=scene.Size(100, 70), icon='emj:Musical_Notes', sounds=drum_sounds, text=None, text_color=self.background_color, parent=self, action=my_button_action, position=scene.Point(sw/6*3, sh/2), animated_icon=True, icon_animation=Animation_Pulse) self.buttons.append(self.my_button_pulse) self.my_button_jump=ButtonNode(size=scene.Size(100, 70), icon='emj:Musical_Keyboard', text=None, text_color=self.background_color, parent=self, action=my_button_action, sounds=piano_sounds, position=scene.Point(sw/6*5, sh/2), animated_icon=True, icon_animation=Animation_Jump) self.buttons.append(self.my_button_jump) self.quiter=ButtonNode(size=scene.Size(32, 32), text='X', text_color='black', parent=self, action=self.quit, sounds=None, position=scene.Point(sw-50, sh-50), borderColor='black', icon=None) self.buttons.append(self.quiter) def quit(self, sender): self.view.close() 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())
-
Very well done!
-
I have noticed a slight error in the game. Occasionally, I will be playing the game, and face a solid wall of gray asteroids. How do I avoid the wall? I can’t. Please, fix this?
-
@Bumbo-Cactoni said:
I have noticed a slight error in the game. Occasionally, I will be playing the game, and face a solid wall of gray asteroids. How do I avoid the wall? I can’t. Please, fix this?
There should always be a gap. What I think is happening here is the gap is being placed above the View Frame and we just cannot see it. I ran some test after changing the following inside
Brush
classdef __init__(self, game): self.game=game self.crateMin=200 self.crateMax=780 self.gaps=list() self.gapSize=4 self.gapMin=4 self.gapMax=6 self.gameObjects=self.game.gameObjects self.startPos=Point(Screen.Width()+128, self.gameObjects.Floor) self.ShieldBoost()
i did not see this happen again but there could still be a chance somehow. all you need to do is limit the hieght for spawning the objects. you could also do a last check to insure there is a gap pressent before returning.
-
@stephen
When I tried to run the code with your updated script, it gave me this error:TypeError
__init__() got an unexpected keyword argument ‘isObsticle’