# Flappy bird browsing

• posted
1

Hello everyone! I'm writing the game and at the beginning now

• posted
1

@Karina

This is an old and sometimes very poorly written clone I did to learn about ai (flappy bird is an awesome game for basic artificial intelligence experiments). I didn’t bother about graphics, but maybe it’s helpful to you.

Run this to play the game:

from scene import *
import sound
import random
import math
import gameExtension as extension
#import nnExtension as nn
A = Action

class MyScene (Scene):

def setup(self):
self.background_color = 'beige'
self.gravity = Vector2(0, -self.size.y/1500)
self.birds = []

self.running = True
extension.setup_walls(self)
extension.update_walls(self)

#self.birdCount = 1 #uncomment if using ai

for x in range(self.birdCount):
pass

def did_change_size(self):
pass

def update(self):
if self.running:
self.running = False
extension.update_walls(self)

for bird in self.birds:
if bird.distance >= 10000: bird.dead = True
self.running = True
extension.count_distance(self, bird)
extension.update_bird(self, bird)
bird.data = extension.get_data(self, bird)

if bird.position.y-bird.size.y/2 <= 0 or bird.position.y+bird.size.y/2 >= self.size.y:
bird.color = 'red'

for wall in self.walls:
if bird.frame.intersects(wall.frame):
bird.color = 'red'
else:
if bird.position.x + bird.size.x/2 >= 0:
bird.position = (bird.position.x - 1, bird.position.y)

def touch_began(self, touch):
self.birds[0].up = True
pass

def touch_moved(self, touch):
pass

def touch_ended(self, touch):
pass

if __name__ == '__main__':
run(MyScene(), PORTRAIT, show_fps=True)

Save this in the same folder as the upper main code as gameExtension.py

from scene import *
import random

self.birds.append(ShapeNode(rect(0,0,10,10)))
bird = self.birds[len(self.birds)-1]
bird.color = 'black'
bird.size = (self.size.x/50, self.size.x/50)
bird.position = (self.size.x/4, self.size.y/2)
bird.z_position = 2
bird.distance = 0
bird.up = False
bird.max_fall_vel = Vector2(0, self.size.y/100)
bird.up_acc = Vector2(0, self.size.y/2)
bird.vel = Vector2(0, 0)
bird.acc = Vector2(0, 0)
bird.data = get_data(self, bird)

def setup_walls(self):
self.wall_distance = self.size.x/4
self.gap_size = self.size.y/6
self.wall_width = self.size.x/14
self.distance_to_next_wall = self.wall_distance + 1
self.walls = []

def count_distance(self, bird):
bird.distance = bird.distance + 1

def update_walls(self):
if self.distance_to_next_wall >= self.wall_distance:
self.distance_to_next_wall = 0
build_wall(self)
else: self.distance_to_next_wall = self.distance_to_next_wall+1

removal = []
for x in range(len(self.walls)):
wall = self.walls[x]
wall.position = (wall.position.x - 1, wall.position.y)

if wall.position.x + wall.size.x/2 < 0:
removal.append(x)

for x in range(len(removal)):
wallIndex = removal[x]-x
wall = self.walls[wallIndex]
wall.remove_from_parent()
self.walls.pop(wallIndex)

def build_wall(self):
posY = random.randint(round(self.gap_size/2), round(self.size.y - self.gap_size/2)) #random position of gap

self.walls.append(ShapeNode(rect(0,0,10,10))) #set up the upper wall
wall = self.walls[len(self.walls)-1]
wall.size = (self.wall_width, self.size.y - posY - self.gap_size/2)
wall.color = 'grey'
wall.position = (self.size.x + self.wall_width/2, self.size.y - wall.size.y/2)
wall.z_position =  1

self.walls.append(ShapeNode(rect(0,0,10,10))) #set up the lower wall
wall = self.walls[len(self.walls)-1]
wall.size = (self.wall_width, posY - self.gap_size/2)
wall.color = 'grey'
wall.position = (self.size.x + self.wall_width/2, wall.size.y/2)
wall.z_position =  1

def update_bird(self, bird):
if bird.up:
bird.up = False
bird.acc = bird.up_acc
else: bird.acc = self.gravity

bird.vel = bird.vel + bird.acc
if bird.vel[1] > bird.max_fall_vel[1]: bird.vel = bird.max_fall_vel

bird.position = bird.position + bird.vel

def get_data(self, bird):
data = []
for x in range(len(self.walls)):
wall = self.walls[x]
if wall.position.x + wall.size.x/2 >= bird.position.x - bird.size.x/2:
y_to_gap = (wall.position.x - wall.size.x/2) - (bird.position.x + bird.size.x/2)
if y_to_gap < 0: y_to_gap = 0
data.append(y_to_gap)
x_to_upper_wall = (wall.position.y - wall.size.y/2) - (bird.position.y + bird.size.y/2)
data.append(x_to_upper_wall)
wall = self.walls[x+1]
x_to_lower_wall = (wall.position.y + wall.size.y/2) - (bird.position.y - bird.size.y/2)
data.append(x_to_lower_wall)
break
distance_to_top = self.size.y - bird.position.y + bird.size.y/2
data.append(distance_to_top)
distance_to_bottom = bird.position.y - bird.size.y/2
data.append(distance_to_bottom)
velocity = bird.vel[1]
data.append(velocity)
return data

• posted
1

@Karina
i hope this helps..

# First

we have A = Action This is simply convenience. Actions are the scene module's Nimation system. You dont have to use this. As shown in the example you can do all manual animation inside the Scene.update() method. called aprox. 60/sec Read more on actions in the Documentation for Actions

# Second

def w(): return get_screen_size()[0]
def h(): return get_screen_size()[1]
def MaxBrushSize(): return 10-2

scene doent handle Global variables very well, so im told, o to avoid thi we have some "Global" variable function. all the do is return the value. vlue here is from
get_screen_size()Tuple(float, float)
the float values is our scren size in Points. More about Points here
MaxBrushSize is just in case we needed a 'clamp' for Arithmatic functions.

# Third

def BaseBlock(parent):
return SpriteNode(Texture('plf:Tile_BoxItem_boxed'),
size=Size(64, 64), parent=parent,
anchor_point=(0.0, 0.0))

def Block(parent):
return SpriteNode(Texture('plf:Tile_BoxCrate_double'),
size=Size(64, 64), parent=parent,
anchor_point=(0.0, 0.0))

def Stone(parent, x):
return SpriteNode(Texture('plf:Tile_BrickGrey'),
size=Size(64, 64), parent=parent,
anchor_point=(0.0, 0.0), position=Point(x*64, 0))

Functions returning Our Sprites. By doing this we clean up our code making it eaier to read and debug. Technically we coud of done this in one function and check the string input for "BrickGrey" to add the minor position change. I split them up o help understanding whats going on fr yourself.

# Next

class TopBrush(Node):
def __init__(self, brushSize, *args, **kwargs):
self.base=BaseBlock(self)
self.size=Size(64, 64)
self.position=Point(w()+(self.size.w), h()-self.size.h)
self.brushSize=brushSize
self.blocks=list([self.base, ])

for x in range(1, self.brushSize):
b=Block(self)
b.position=(self.base.position[0], self.base.position[1] - x*b.size[1])
self.blocks.append(b)

class BottomBrush(Node):
def __init__(self, brushSize, *args, **kwargs):
self.base=BaseBlock(self)
self.size=Size(64, 64)
self.position=Point(w()+(self.size.w), 0)
self.brushSize=brushSize
self.blocks=list([self.base, ])

for x in range(1, self.brushSize):
b=Block(self)
b.position=(self.base.position[0], self.base.position[1] + x*b.size[1])
self.blocks.append(b)

Pretyslf explnitoy here. simply grouping our sprits into two secions and setting thier position for pillar like setup. TopBrush and BottomBrush. Nothing els speceal here.

# Lastly

Now that we have everything prepared we can play with it ☺️.

class MyScene (Scene):
def setup(self):
self.background=SpriteNode(Texture('plf:BG_Colored_grass'),
size=Size(w(), h()), position=self.size/2, parent=self)
self.preset=[(1, 7),(2, 6),(3, 5),(4, 4),(5, 3),(6, 2),(7, 1)]
self.i=0.0
self.brushSpawnTimer=3.0
self.brushes=list([])
self.scrollSpeed=40

for x in range(int((w()*128)/64)):
self.brushes.append(Stone(self, x))

setup() is called after the Scene object is returned bu before Event Loop Starts so here you can use Scene Variables such as size or bounds to setup your Game screen Invironment.
*Note: you can overide the __init__ method but you must call to Scene.__init__(self, *args, **kwargs) otherwise your loop will become unstable and crash. generally no reason to call it. setup() usualy is all u need .

if self.i > self.brushSpawnTimer:
bb=BottomBrush(choice[0])
tb=TopBrush(choice[1])
self.brushes.append(bb)
self.brushes.append(tb)
self.i=0.0
self.brushSpawnTimer = random.randrange(3, 6)
else:
sb=Stone(self, (w()+128)/64)
self.brushes.append(sb)

def Remove_Brush(self, brush):
self.brushes.remove(brush)
brush.remove_from_parent()

Methods Add_Brush and Remove_Brush are very important. there would be no level without Add lol and Without Remove we could build up memory usage and thats never good. always clean up after yourself 😬🙃

def Scroll(self, brush):
x=brush.position[0]-self.scrollSpeed*self.dt
y=brush.position[1]
return Point(x, y)

def update(self):
self.i += self.dt
for brush in self.brushes:
if brush.position[0] <= -64:
self.Remove_Brush(brush)
brush.position = self.Scroll(brush)

Finaly our Scroll and update methods.. these two bring it all to life.. Only thing to realy spotlight here for you is self.dt
this is the Time Delta, time between calls. in this case its the time between Frames and usually 0.00165.... We are using it for two uses. one is a timer for spawning our brushes and other is to smooth out the movment of our objects to make it visually appealing..

I hope thi helps you understand hts going on. Scene is a powerful tool and not just for game design but you have a long frustrating jurny ahead of you.. but its worth it ☺️🤓🤓🤓 i would suggest you look into using scene and ui modules togeather.you only need to call fom scene import * and ui is already imported in scene. ready or you. if ou do this you get a much more devloper freindly User interface along with your game loop. all you need to do is connect your Scene class to a scene.SceneView and add it to your CustomView with self.add_subview().

Ill be glad to help with anything else you need.

• posted
0

@Drizzel well done 🙃🤓😎

• posted
1

@stephen thanks for the kind words, but some things are clumsy at best. Your summary is awesome, though. Although I am really glad that I can help here :) That way I can return at least a small amount of the support this community here has given me

• posted
0

@Drizzel you say you clumsy, but I don't know how to do theese things at all)
your explanations helped to understand the beginnin, I think it'll take time to understand it all
Do you know anything like Clock in pygame to work with time? I need to make a new column every 10 secs for example

• posted
0

If you need inspiration, https://github.com/Pythonista-Tools/Pythonista-Tools/blob/master/Games.md features a Flappy Bird style game called Jumpy Octopus.

• posted
0

@Drizzel i see now what brushes are. Do you know some article to read about it? But what difference between w() and self.size.w?
And MaxBrushSize() just returns 8?
And what difference between creating Potint and just passing a tuple to the position argument?
Sorry about bombarding you with questions)

• posted
0

@Karina said:

@Drizzel i see now what brushes are. Do you know some article to read about it? But what difference between w() and self.size.w?
And MaxBrushSize() just returns 8?
And what difference between creating Potint and just passing a tuple to the position argument?
Sorry about bombarding you with questions)

I'll just forward that to @stephen for now (I'm rather pressed on time for the next few hours), he's the mastermind behind brushes.

• posted
0

@stephen thank you for help and can you give me some articles about brushes and games on pythonista?
And do you know a way to work with time like in pygame.Clock? I already made a column move and need to add column every 5 seconds

• posted
0

@Karina said:

@Drizzel you say you clumsy, but I don't know how to do theese things at all)
your explanations helped to understand the beginnin, I think it'll take time to understand it all
Do you know anything like Clock in pygame to work with time? I need to make a new column every 10 secs for example

The update(...) function (is used in my code and the code by @stephen) is executed 60 times a second (as long as your device can handle the load). Here's a good explanation. You can use self.dt to check how much time has passed since the last frame was calculated, and self.t to check for how long the scene has been running.
Then just do put this line into setup(...):

self.time_of_last_column = self.t

and merge this with your update(self):

def update(self):
if self.t - self.time_of_last_column >= 10:
#put the code to place a new column here
self.time_of_last_column = self.t

• posted
0

@Drizzel yes I have the docs in pythonista

I tried to do it like that, but I only get the black screen that I can't even close

def update(self):
time_passed = 0
while True:
time_passed += self.dt
if time_passed >= 0.5:
print(time_passed)
time_passed = 0
self.column_moves()

• posted
0

You have to remove the loop, like this:

def update(self):
time_passed += self.dt
if time_passed >= 0.5:
print(time_passed)
time_passed = 0
self.column_moves()

Everything inside update() gets executed 60 times per second. Just put self.time_passed = 0 in setup()

• posted
0

This is a bit smarter:

from scene import *
import sound
import random
import math
A = Action

class MyScene (Scene):
def setup(self):
self.background_color = 'white'

self.blocks = []
for x in range(5):
block = ShapeNode(rect(0,0,10,10))
block.color = 'black'
block.size = (30, 30)
block.position = (self.size.x - 30, x*block.size[1] + block.size[1]/2)
self.blocks.append(block)

self.previous_time = self.t #self.t is the time that the game has been running

def update(self): #everything in Here gets called 60 times a second
if self.t - self.previous_time >= .5:
self.previous_time = self.t
self.move_blocks()

def move_blocks(self):
for block in self.blocks:
position = block.position
new_x = position[0] - 10
block.position = (new_x, position[1])

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

• posted
0

@stephen about your brushes I began to implement it by I don 't understand some things:
what the difference between w() and self.size.w and
MaxBrushSize just returns 8??
And the program and the graphics look great😊

• posted
0

from scene import *
import random
import time

A = Action()

def Ground(parent):
return SpriteNode('plf:Ground_Grass', parent=parent)

def ColumnBlock(parent):
return SpriteNode('plc:Brown_Block', parent=parent)

class BottomBrush(Node):
def __init__(self):
self.ground = GroundBlock(self)
self.position = (self.size.w)

class Game(Scene):
def setup(self):
self.background_color = '#99d7ff'
#to track when 5 seconds passed and need to add a new column
self.time_passed = 0
#add the first column so you don't have to wait for it 5 seconds
self.columns = []
x = 0
ground = Node(parent=self)
ground.z_position = -1
#building the upper and lower ground
while x < self.size.w:
lower_tile = SpriteNode('plf:Ground_Grass', (x, 30))
higher_tile = SpriteNode('plf:Ground_GrassCenter', (x, 738))
x += 60

self.speed = 1

def update(self):
self.time_passed += self.dt
if self.time_passed >= 5:
self.time_passed = 0
self.column_moves()

lower = random.randint(0, 360) // 64
higher = 9 - lower
#building the lower part
y = 35
for i in range(lower):
block = ColumnBlock(parent=self)
block.anchor_point = (0.5, 0)
block.position = (self.size.w, y)
self.columns.append(block)
y += 64
#building the higher part
y = 738
for i in range(higher):
block = ColumnBlock(parent=self)
block.anchor_point = (0.5, block.size.h)
block.position = (self.size.w, y)
self.columns.append(block)
y -= 64

def column_moves(self):
actions = [A.move_by(-self.size.w, 0, 30/self.speed), A.remove()]
for i in self.columns:
i.run_action(A.sequence(actions))

run(Game())```

For now I have this. It makes columns move just like I need. There will be the bird and the functions it needs, and I'm done😀

• posted
0

@Karina

Outstanding work so far! im very impressed on how fast you are grasping this.

### what the difference between w() and self.size.w?

In my example w() is recieving the width size of the screen directly. self.size.w is reference to the current Node's width. Yes when used inside your Subclass of scene.Scene this will be the same value. but this is only becasue you are initiating its View by using the module level run() function. (run always launches in fullscreen). but in the future you may notwant fullscreen and this means you would use a custom ui.View class then add a SceneView to it. now if you use the w() function you will get screen width as expected but now your self.size.w will return a different value referencing the SceneView's frame (frame ⇨ Tuple(x, y, width, height)) you can also retrieve this uing MySceneView.frame[2]. in our case i didnt needto use the w() function but we practice how we wantto playon game day. 😎 good habets produce great programs.

### MaxBrushSize just returns 8??

yes i know the return 10-2 seems useless. but maybe down the road you want to create, lets say, powerups. one might be the gaps get larger bfor n seconds. since we already have this in out code all we need to do is make a quick change.. this would be the replacement ⥥

def MaxBrushSize(mod):
return 10 - mod

then somwhere in your code you you add somthis similar to this

...
def StartGapPowerUp(self, value ):
self.maxBrushSize = MaxBrushSize(value)
time.sleep(10) #waits 10 seconds
self.maxBrushSize = MaxBrushSize(default)
...

ive been playthingwith game development for many years in multiple languges so i have built some habits that i dont notic i do anymore lol.

next post will be some notes nd pointers of you latest code posted and ill put a script showing my previous answeres in action! stay tuned 🤓🤓

• posted
0

1. self.point=Point(w() + self.position.w, h() - self.size.h)
If w() and self.size.w are the same here, then we got 2*self.position.w? And why instead of sec arg don't just right 0??

2. When I tried to use sleep(), my screen just got black and I couldn't close it. And also was a problem and it all hang and didn't move. I did smth and fixed it, don't know how😅. But why theese things can happen?

I have hundred of questions on each couple lines)

• posted
0

@Karina

'''
I realized i didnt fully implemate Brushes and that might have been confusing.
so ill post a new script using actual brushes.

and as a bonus for showing you actually want to learn and not just copy/paste
ill add some extra functionality for your 'cookbook'.

i do apologise about the amount on notations lol there beingbalot of comments
doesnt mean its a bd script. most is advice. i did change a few things mostly
for your convenience and to smooth out animation.

but first here is some notes on hat you have provided thus far..
'''
from scene import *
import random
import time

A = Action()

'''
i added these so you only have one place to change sizes instead of
bouncing around
sw ⇒ screen width
sh ⇒ screen height
bw ⇒ block width
bh ⇒ block height
so ⇒ screen orientation
lw ⇒ level view port width
lh ⇒ level view port height
'''

def sw(): return get_screen_size()[0]
def sh(): return get_screen_size()[1]
def bw(): return 64
def bh(): return 96
def so(): return 1 if sw() < sh() else 2
def lw(): return 1024 if so() is 2 else 768
def lh(): return 1024 if so() is 1 else 768

def Ground(parent):
return SpriteNode('plf:Ground_Grass', parent=parent, size=Size(bw(), bh()))

def ColumnBlock(parent):
return SpriteNode('plc:Brown_Block', parent=parent, size=Size(bw(), bh()))

'''
not sure what happened here but as you
probably know if called wil throw exceptions.
im assuming this is why you dont actually use it.

self.position = (self.size.w)

first a regular Node object hase no size property.
BUT it has a bbox wich is a scene.Rect with a width value.
even with that said a poisition property much recieve a
2 Tuple (x, y) preferably a Point object but not neccesary.
i.e:
self.position = Point(x, y)
let me know if your having a problem here it seem as your
trying to use self to refer to your Scene class. and you can.
but not through self. if your not sure how self work i can tell
u jut say
'''
class BottomBrush(Node):
def __init__(self):
self.ground = GroundBlock(self)
self.position = (self.size.w)

class Game(Scene):
def setup(self):
self.background_color = '#99d7ff'
#to track when 5 seconds passed and need to add a new column
self.time_passed = 0
#add the first column so you don't have to wait for it 5 seconds
self.columns = []
x = 0
ground = Node(parent=self)

#building the upper and lower ground
'''
Generally a while loop is not a very big deal but in this
case its not a great idea.
i say this because what if for some unknown reason
self.size.w is somthing crazy like 2389488754589433357.
🤓😅 unlikely i know but just for fun...
now your game is hung up seeming like it is frozen to end user.
now a for loop, at least i feel, is much safer in this. matter.
but to be honest.. a premade pillar object would be best use. ill
show this in next post.
'''
while x < lw()+bw():
lower_tile = SpriteNode('plf:Ground_Grass',
position=Point(x, 0), size=Size(bw(), bw()), anchor_point=(0.5, 0.0))
higher_tile = SpriteNode('plf:Ground_GrassCenter',
position=Point(x, lh()), size=Size(bw(), bw()))
x += bw()

self.speed = 1 # Node.speed is defaulted to 1.0
'''
changed z_position to keep to and bottom over blocks
'''
ground.z_position = 999
def update(self):
self.time_passed += self.dt
'''
good job with >= hen comparing floats in this manner never use ==

sence your calling self.column_moves() every frame we can manually
move our blocks. (see method comment)
# note: changing "5" to eithere a random int or an instance property
will  alow a more dynamin level generation.
'''
if self.time_passed >= 5:
self.time_passed = 0
self.column_moves()

lower = random.randint(1, 360) // bw()
higher = 9 - int(lower)
#building the lower part
y = 35
'''
here you can get rid of the variable "lower"
this should reduse memory use. for this game it
doesnt matter but in future it could make a diference.

for i in range(random.randint(0, 360) // 64):

this insures the memory is released after forloop.

also i would suggest moving
block.anchor_point = (0.5, 0)
and
block.position = (self.size.w, y)
to your ColumnBlock function like this

def ColumnBlock(parent, x, y):
return SpriteNode('plc:Brown_Block',
anchor_point=(0.5, 0),
position=Point(x, y),
parent=parent)

then in your for loop make your "i" var useful and get rid of "y"

for i in range(lower):
self.columns.append(ColumnBlock(self, self.size.w, i*64))

now we dont add a new block to memory then copy to list.  we
just add one to list and memory at same time.

anchor_point is values 0 to 1
0 being botom left a 1 being top/right
(1, 1) would be top right
(0.5, 0.5) would be center.
changed block.size.h to 1.0
'''
for i in range(1, lower+1):
block = ColumnBlock(parent=self)
block.anchor_point = (0.5, 0.5)
block.size= Size(bw(), bh())
block.position = (lw(), bh()/3+i*bw())

block.z_position = -i
self.columns.append(block)
y += bw()
#building the higher part
y = lh()
for i in range(1, higher+1):
block = ColumnBlock(parent=self)
block.anchor_point = (0.5, 0.5)
block.position = (lw(), (lh()-i*bh()/2))
block.z_position = i
self.columns.append(block)
y -= bh()

'''
great work on this part only sugestion would be to set your interp timing.
probably TIMING_SINODIAL  in this case cuz its mich smoother than linear.
and this will go where you have "30/self.speed". and this oddly doesnt thow
an excption and id avoid "0" for duration. 0.1 seems fast enough. or even
0.01 if needed. so somthing like ths.

A.move_by(-self.size.w, 0.1, TIMING_SINODIAL)

you also dont need remove. this is meant o remove objects not Actions.
sinve you pass none or () its does nothing.

one more thing the "self.speed is used to modify Action speed. but its
automatically implemented. to if you want a 2x animation speed just set
self.speed = 2  and everything else is done for you."

you also should useba Node object to group the sprites this way theres
no need for the for loop. you just move the parent and child nodes will
follow.
i changed the folowing method so that it stops the "jerking"bwhen it
moves. they now move smoothly

::from update comment::
with that all said, lets be nice to our cpu and instead of runing an Action
proccess lets just do some simple math. im not changing thisone but i would
write the following:
#note: i wouldnt do this for every block i would group the colums (◕_◕)
#note: velocity would be set inside startup/__init__ and can be used
#      with powerups ☺️
for i in self.columns:
i.position = Point(
i.position[0] - self.velocity*self.dt, i.position[1])

'''

def column_moves(self):
actions = [A.move_by(-self.size.w/2, 1, TIMING_SINODIAL)]
for i in self.columns:
i.run_action(A.sequence(actions))

'''
dont forget you can set some properties when calling the  "run()" function

scene.run()
## you know this one lol ##
⑴ scene
## alloud orientations.
-   FROM DOC: Important: The orientation
-   parameter has no effect on iPads starting with iOS 10 because
-   it is technically not possible to lock the orientation in an app
-   that supports split-screen multitasking. ##
⑵ orientation=DEFAULT_ORIENTATION
## frame rate controle
FROM DOC: By default, the scene’s update() method is called 60
times per second. Set the frame_interval parameter to 2 for
30fps, 3 for 20, etc. ##
⑶ frame_interval=1
## this game wont need but here you go
FROM DOC: Set this to True to enable 4x multisampling. This has
a (sometimes significant) performance cost, and is disabled by
default. ##
⑷ anti_alias=False
## explains itself. i tent do make my own so i can control the
color and position. ##
⑸ show_fps=False
## you shouldnt need this for this game if kept simple
⑹ multi_touch=True
)
'''
run(Game())

# now to write that version two example for u. and again great work!

• posted
0

@Karina said:

1. self.point=Point(w() + self.position.w, h() - self.size.h)
If w() and self.size.w are the same here, then we got 2*self.position.w? And why instead of sec arg don't just right 0??

2. When I tried to use sleep(), my screen just got black and I couldn't close it. And also was a problem and it all hang and didn't move. I did smth and fixed it, don't know how😅. But why theese things can happen?

I have hundred of questions on each couple lines)

### 1.

self.point=Point(w() + self.position.w, h() - self.size.h) If w() and self.size.w are the same here, then we got 2self.position.w? And why instead of sec arg don't just right 0??*

self.position.w should be self.position.x
translated self.point=Point(w() + self.position.w, h() - self.size.h) means
Node's Position is a Point Object with x coordinate at screen width plus node's position x and y coordinate at screen height minus nodes hieght.

or in other words

x = screen_width + self.position.x
y = screen_hieght - self.size.hieght
self.position = Point(x, y)

### 2.

When I tried to use sleep(), my screen just got black and I couldn't close it. And also was a problem and it all hang and didn't move. I did smth and fixed it, don't know how😅. But why theese things can happen?

this was my fault lol i forgot you need to att a decorator from ui module

@ui.in_background
time.sleep(5)

this will run sleep on a different thread than your scene

• posted
0

@Karina

never too many questions

Internal error.

Oops! Looks like something went wrong!