omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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.


    SpriteKit wrapper

    Pythonista
    6
    31
    13562
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • mikael
      mikael last edited by mikael

      Demo gif

      Got excited about using SpriteKit, and quickly noted that it is not fun to use without a Python wrapper, so.

      SpriteKit is interesting mainly if you need some 2D physics like collisions or field effects.

      Here‘s a simple example demonstrating some features available so far:

      scene = Scene(
        background_color='black',     #1
        physics=SpacePhysics)         #2
        
      class SpaceRock(SpriteNode):    #3
        
        def __init__(self, **kwargs):
          super().__init__(**kwargs)
          self.angular_velocity = random.random()*4-2
          self.touch_enabled = True   #4
          
        def touch_ended(self, touch): #4
          self.velocity = (
            random.randint(-100, 100),
            random.randint(-100, 100)
          )
        
      ship = SpriteNode(
        image=ui.Image('spc:EnemyBlue2'), 
        position=(150,600),
        velocity=(0, -100),          #5
        parent=scene)
        
      rock = SpaceRock(
        image=ui.Image('spc:MeteorGrayBig3'), 
        position=(170,100),
        velocity=(0,100),
        parent=scene)
        
      scene.view.present()
      

      Points to note:

      1. Many familiar features work as they do in the scene module, like setting colors etc.
      2. Physics settings like gravity, linear damping (air friction) and restoration (bounciness) can be set with convenient packages.
      3. All nodes are inheritable.
      4. Individual nodes are touchable (and thus support gestures as well).
      5. Physics are accessible without explicitly playing with SpriteKit physicsBody.

      This is work in progress, available on github. If you are interested in using SpriteKit in this way, let me know and we can guide the wrapping progress in a useful way.

      JonB 1 Reply Last reply Reply Quote 2
      • mikael
        mikael last edited by

        Here's a pool/billiards table I am using as a testbed for the SpriteKit wrapper.

        Pool table

        You can actually play 8-ball with it, but mainly demo-pool.py tests and demonstrates how to:

        1. Create a "hollow sprite" - the sides of the pool table, for the balls to bounce in.
        2. Make a node (the table) unmoveable by setting dynamic to False.
        3. Make nodes for display only (the pockets) by setting body to None.
        4. Create a gravity field node (in the pockets) to simulate the small slope into the pockets.
        5. Limit the effect of the gravity field to a small circular region - first version pulled the balls clear across the table, which made the game a bit too easy. :-)
        6. Manage the touches on the cue ball with its internal coordinate system that of course rotates with the ball.
        7. Use category_bitmask and contact_bitmask to detect when the ball enters a pocket.
        8. Use update to make changes that cannot be made while the simulation step is running (moving balls to the side of the table).
        9. Use category_bitmask and collision_bitmask to temporarily prevent a pocketes cue ball from interacting with the table or other balls when it is being moved back to the table.

        I think that this also demonstrates the relative power of SpriteKit, as the demo is only about 200 lines of code.

        1 Reply Last reply Reply Quote 1
        • mithrendal
          mithrendal last edited by mithrendal

          Very cool stuff !! 😃

          1 Reply Last reply Reply Quote 0
          • cvp
            cvp last edited by

            You're a champion, but not only of pool/billiards table 😀

            1 Reply Last reply Reply Quote 0
            • SmartGoat
              SmartGoat last edited by

              What a masterpiece, you’re an awesome developer @mikael !

              1 Reply Last reply Reply Quote 1
              • mikael
                mikael last edited by

                Another testbed/demo, a Hill Climb Racing clone, code here.

                Demo video

                Demonstrates how to:

                • Generate an unending terrain.
                • Use a smooth curve as the top of the terrain.
                • Pin the wheels to the car, allowing them to roll.
                • Setting several physical constants (poorly, as is evident already from the short animation above).
                • Set a camera to keep the car visible, leading a bit.
                • Anchor a hud element (the score) to a constant relative place on the screen (label as a child of the camera node, with a bit of non-SpriteKit extra to make it more intuitive).
                • Creating a fully rotation-responsible scene without any references to the screen size.

                150 lines

                cvp 1 Reply Last reply Reply Quote 0
                • cvp
                  cvp @mikael last edited by

                  @mikael whaaaa so a nice effect with a so little code. I'm jealous, super

                  1 Reply Last reply Reply Quote 0
                  • JonB
                    JonB @mikael last edited by JonB

                    Does anyone have any of the old skscene examples from the early pythonista1.6 betas. At one point I think I had copied them after the scenekit or whatever it was called module was abandoned by omz, but I'd have to dig around in the backups.
                    Also, iirc, there was a nice level editor that was supposedly pure python.

                    Just thinking this might give some other thoughts on things to implement. I remember a clock with falling numbers, and maybe a breakout clone.

                    Anyway, this is some cool stuff @mikael.

                    cvp mikael 2 Replies Last reply Reply Quote 0
                    • cvp
                      cvp @JonB last edited by

                      @JonB perhaps here

                      1 Reply Last reply Reply Quote 0
                      • cvp
                        cvp last edited by

                        If you search for old scripts, try https://github.com/tdamdouni/Pythonista

                        1 Reply Last reply Reply Quote 0
                        • mikael
                          mikael @JonB last edited by

                          @JonB, oh man, yes, looking at some of the scripts in tdamdouni repo, they import an sk module which clearly has many or all the nodes defined. And there are pysk files which define game levels.

                          Now if we could just find the sources these refer to.

                          1 Reply Last reply Reply Quote 0
                          • cvp
                            cvp last edited by cvp

                            Here https://github.com/tdamdouni/Pythonista/blob/master/omz/SKExample.py

                            And https://github.com/tdamdouni/Pythonista/blob/master/omz/sk.py

                            1 Reply Last reply Reply Quote 0
                            • JonB
                              JonB last edited by

                              Yeah, that GitHub has a bunch of the other examples, including that clock I remember, and pysk files. The sk module was a c module.

                              mikael 1 Reply Last reply Reply Quote 0
                              • mikael
                                mikael @JonB last edited by

                                @JonB, no hope for finding a ready-made, Pythonista-runnable sk module then, but the pure Python level editor sounds nice, and could probably be made to work with this wrapper. Was it made by @omz?

                                1 Reply Last reply Reply Quote 0
                                • JonB
                                  JonB last edited by

                                  In retrospect, the editor was not pure python, but the load_sk or whatever was. It is possible (haven't tried) that the pysk editor still works -- for many versions after the sk module was removed, when you opened a pysk, pythonista had a custom editor, very similar to opening a pyui. Iirc, it let you add backgrounds, by adding assets on a grid, and also let you add pins and specify gravity or physics... But it has been a while. Take a look at the pysk files which are just json.

                                  1 Reply Last reply Reply Quote 0
                                  • mikael
                                    mikael last edited by mikael

                                    Some more demos.

                                    First, here is the script by @jbking that got me started on the SpriteKit path. Below you can see the same implemented in the wrapper, with every touch dropping a random rectangular or circular block. With couple of blocks placed on the platform at the start, this becomes a surprisingly addictive game of "can I clear the platform".

                                    Drop pic

                                    Technically, the interesting bit here is how easy it is to make the scene work with rotation by just placing the anchor point in an appropriate place - in this case at (0,5,0), equal to the center of the bottom edge.

                                    Another oldie but goodie is dropping random doodles:

                                    Draw animation

                                    Making this happen lead to surprisingly many challenges with using paths as physics bodies:

                                    • SpriteKit has a method that creates a physics body from a path, but this method is very finicky, requiring the path is a counterclockwise and convex, which is rarely what you have at hand.
                                    • Thus I included a method to create a convex hull surrounding the points of the path.
                                    • SpriteKit also has a method for creating a smooth spline over a set of points, but no way to continue the path thus created, and the famously "opaque" CGPath is quite hard to inspect & manipulate in Python.
                                    • So I included a bit kludgy methods that get the points out of a ui.Path, and the Bézier definitions out of the spline created by SpriteKit.
                                    • With these, the API feels mostly natural, and you can provide either a ui.Path or a set of points to create the ShapeNode, and choose to have smoothing applied or not.

                                    Smoothing image

                                    • Convex hull is not a 100% solution for paths, as concave spots or arcs curving out between two points are not accurately represented.
                                    • Thus there is an option to use a texture-based body instead of the convex hull. According to Apple, this is the least performant option, but probably ok in most cases, so I made it the default.
                                    • In the doodle demo, above, every other doodled object uses a hull and every other a texture as the physics body, and I find it hard to tell which is which.
                                    1 Reply Last reply Reply Quote 0
                                    • ccc
                                      ccc last edited by

                                      https://github.com/TheAlgorithms/Python/blob/master/divide_and_conquer/convex_hull.py

                                      1 Reply Last reply Reply Quote 0
                                      • mikael
                                        mikael last edited by mikael

                                        Time for the space race!

                                        Space race demo animation

                                        Features tested:

                                        • Animation Actions - Many but not all of the multitude of actions have been enabled, with a little addition of Python syntax - you can choose to use a set instead of Action.group, and a list instead of Action.sequence, like in this "pulsing" example for the race course buoys:
                                            A = Action
                                            node.run_action(
                                              A.forever([
                                                A.scale_to(1.2, timing=A.EASE_IN_OUT),
                                                A.scale_to(1.0, timing=A.EASE_IN_OUT),
                                              ])
                                            )
                                        
                                        • EmitterNode can be used for particle effects like the ship's thrust.
                                        • Background tiling is a custom feature of the CameraNode - you provide a tile and a factor for relative movement, like here:
                                            self.camera.layers.append(Layer(
                                              Texture('background.png'), pan_factor=0.2, alpha=0.4))
                                        

                                        The layers in the layers list are ordered from closest to furthest away.

                                        • EffectNode is used for the background performance, to cache all the individual tiles as one bitmap.

                                        Also planning to use this as a testbed for various field effects, inverse kinematics and remote play.

                                        1 Reply Last reply Reply Quote 2
                                        • mikael
                                          mikael last edited by

                                          Introducing Vertigo Vortex! Coming to you courtesy of "little" help from @JonB.

                                          Vortex demo run

                                          This demonstrates both visual warping and a vortex field effect.

                                          You can read more about warping in Apple docs. Here I included a custom spiral warping effect, which resembles some of the shader effects except it is much nicer to code in Python than in the shader quasi-C.

                                          Applying the effect:

                                          spritenode.warp = WarpGrid(21,21).set_spiral(-math.pi*2)
                                          

                                          Parameter of set_spiral tells how much the points on the outer circle move counter-clockwise; in the example case, full 360 degrees clockwise. Spiral effect then happens when points closer to the center are rotated less.

                                          Sequences of warps can be animated, e.g. like this:

                                          warps = [
                                            WarpGrid(21,21).set_spiral(-math.pi/1.25/10*i) for i in range(11)
                                          ]
                                          spritenode.run_action(Action.warps(warps, duration=3.0))
                                          

                                          Warp animation

                                          About the magic numbers 21,21 in the grid initialization - I do not know how detailed the grid must be, but I expect some detail is needed for most effects, as different grid sizes produce very different results. You can see the difference below, where all the images except the origonal apply the same 90-degree counter-clockwise effect, only with different level of granularity:

                                          Effect of grid size

                                          With the vortex physics field effect, I had to cheat, since I could not get the SpriteKit vortex field to work.

                                          With field strength 0.003, the field was still throwing the ship around much too hard, yet with strength 0.002 the field turned off completely.

                                          So instead of fighting this, I opted to manually apply a tangential force in the update. Works fine here, but could be a performance topic if you need more complex things.

                                          1 Reply Last reply Reply Quote 1
                                          • JonB
                                            JonB last edited by JonB

                                            Did you play with the falloff parameter of the vortex? The field strength falls off as
                                            pow(distance - minRadius, -falloff)

                                            So depending on what your scaling parameters are, you might try a smaller falloff, and maybe a larger minRadius. I think the default falloff is 2, meaning as your distance doubles, the strength falls off by 4x. Looks like you used 100 meaning when the distance doubles, the strength falls off by 2**100! Your cheat effectively used falloff of 0. I bet if you crank the strength back up, and set falloff to 0, or something in the .5-2 range, it will work as expected.

                                            mikael 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors