Hello everyone! I'm writing the game and at the beginning now
Forum Archive
Flappy bird
from scene import *
import random
class Column(SpriteNode):
def __init__(self, **kwargs):
SpriteNode.__init__(self, 'plf:Tile_BoxCrate_double', **kwargs)
class Game(Scene):
def setup(self):
self.background_color = '#99d7ff'
x = 0
ground = Node(parent=self)
while x < self.size.w:
lower_tile = SpriteNode('plf:Ground_Stone', (x, 30))
higher_tile = SpriteNode('plf:Ground_Stone', (x, 738))
x += 60
ground.add_child(lower_tile)
ground.add_child(higher_tile)
self.add_column()
def add_column(self):
lower = random.randint(0, 360) // 64
higher = random.randint(0, 360) // 64
y = 45
for i in range(lower):
column = Column(parent=self)
column.anchor_point = (0.5, 0)
column.position = (self.size.w, y)
y += 64
y = 738
for i in range(higher):
column = Column(parent=self)
column.anchor_point = (0.5, column.size.h)
column.position = (self.size.w, y)
y -= 64
run(Game())
This only makes ground and two columns at the end of the screen. The problem is that whenever I run this, the columns always at the same size. But I use random here, so they should get different each time. I can't get why is it so
Hello @Karina
im going to look into your code and ill br back with somthing for you. i do first want to suggest that instead of Random int you create Brushes kind of like Minecraft did for Trees. you would creat a class to for your brush objects then place them in a list. then use Random Choice instead and this randomly selects from list. gives you control of the objectvdesigns and easier to manage i find than dealing with ranges. that ssid ill be back βΊοΈππ€
I am new in programming and this is my first program in scene, so I don't know what are theese things. But thank you anyway
@Karina the issue lies in line 22.
Since add_column is in the loop, it will get called plenty of times. This results in a lot of columns stacked on top of another, and it is very probable that at least once these columns has the maximum number boxes, and therefore the βsmallestβ gap.
Just remove one of the indents in line 22 to fix this.
Btw, what @stephen said is certainly worth looking into, like just about any of his suggestions
@Karina
heres is example of using brush like objects with scrolling nd random (not too random) spacing. if you have ny questions please ask!
@Drizzel thank you, i alwys try to help out tht way i get to learn kong the wy aswell ππ€π€
from scene import *
import sound
import random
import math
A = Action
def w(): return get_screen_size()[0]
def h(): return get_screen_size()[1]
def MaxBrushSize(): return 10-2
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))
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)
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))
def Add_Brush(self, choice):
if self.i > self.brushSpawnTimer:
bb=BottomBrush(choice[0])
tb=TopBrush(choice[1])
self.add_child(bb)
self.add_child(tb)
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()
self.Add_Brush(random.choice(self.preset))
def did_change_size(self):
pass
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)
def touch_began(self, touch):
pass
def touch_moved(self, touch):
pass
def touch_ended(self, touch):
pass
if __name__ == '__main__':
run(MyScene(), show_fps=False)
Quick Note
The example i provided is for landscpe if you run portrait the gapps will not adjust. this can be handled by checking orientation and swapping the preset lists accordingly
@stephen I don't understand to much things, I've just read the tutorial and tried to do my own game.
I'll try to get it with time
@Karina il give a bit of a run down just give me few min to write it βΊοΈ
@Drizzel yes I got it. Now it works how it should
@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):
extension.add_bird(self)
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
if not bird.dead:
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'
bird.dead = True
for wall in self.walls:
if bird.frame.intersects(wall.frame):
bird.color = 'red'
bird.dead = True
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
def add_bird(self):
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.dead = False
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)
self.add_child(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.add_child(wall)
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
self.add_child(wall)
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
@Karina
i hope this helps..
First
we have
A = ActionThis is simply convenience.Actionsare thescenemodule's Nimation system. You dont have to use this. As shown in the example you can do all manual animation inside theScene.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
Globalvariables 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
MaxBrushSizeis 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
stringinput 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.
TopBrushandBottomBrush. 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 .
def Add_Brush(self, choice):
if self.i > self.brushSpawnTimer:
bb=BottomBrush(choice[0])
tb=TopBrush(choice[1])
self.add_child(bb)
self.add_child(tb)
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()
self.Add_Brush(random.choice(self.preset))
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.
@Drizzel well done ππ€π
@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
@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
If you need inspiration, https://github.com/Pythonista-Tools/Pythonista-Tools/blob/master/Games.md features a Flappy Bird style game called Jumpy Octopus.
@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)
@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.
@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
@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
@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)
self.add_column()
time_passed = 0
self.column_moves()
You have to remove the loop, like this:
def update(self):
time_passed += self.dt
if time_passed >= 0.5:
print(time_passed)
self.add_column()
time_passed = 0
self.column_moves()
Everything inside update() gets executed 60 times per second. Just put self.time_passed = 0 in setup()
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.add_child(block)
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)
@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π
```
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 = []
self.add_column()
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
ground.add_child(lower_tile)
ground.add_child(higher_tile)
self.speed = 1
def update(self):
self.time_passed += self.dt
if self.time_passed >= 5:
self.add_column()
self.time_passed = 0
self.column_moves()
def add_column(self):
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π
@Karina
Outstanding work so far! im very impressed on how fast you are grasping this.
first ill answer your questions π€
what the difference between w() and self.size.w?
In my example
w()is recieving the width size of the screen directly.self.size.wis reference to the currentNode'swidth. Yes when used inside yourSubclassofscene.Scenethis will be the same value. but this is only becasue you are initiating itsViewby using the module levelrun()function. (run always launches in fullscreen). but in the future you may notwant fullscreen and this means you would use a customui.Viewclass then add aSceneViewto it. now if you use thew()function you will get screen width as expected but now yourself.size.wwill return a different value referencing theSceneView'sframe (frame β¨ Tuple(x, y, width, height)) you can also retrieve this uingMySceneView.frame[2]. in our case i didnt needto use thew()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-2seems useless. but maybe down the road you want to create, lets say, powerups. one might be the gaps get larger bfornseconds. 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 π€π€
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)
@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 = []
self.add_column()
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()
ground.add_child(lower_tile)
ground.add_child(higher_tile)
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.add_column()
self.time_passed = 0
self.column_moves()
def add_column(self):
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.
use this instead..
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!
@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
def add_column(self):
time.sleep(5)
this will run sleep on a different thread than your scene
@Karina
never too many questions
@Karina now im off to write the game in the way i would. so you can compare. in no way is MY way the best or even the most correct. but it is the way i learned to implement different objects and functionality over the years.
@Karina just an update ive been a bit busy but i might have my project ready in the next 20 hours or so. it wont have a lot of comments but ill put a few. but im trying to use only descriptive naming so it should not beva problem.hope to see what you learned from this project π€π€π€
@stephen said:
self.point=Point(w() + self.position.w, h() - self.size.h) <
Ah, I forgot that we're inside Node, not Scene
i understand what lw() does, but what is lower port width? And lw() is the returns the width, if add bw(), we should get beyond the screen?
self.size.w is somthing crazy like 2389488754589433357
I went to check the self.size.w, and it is 1024. What do you it is smth like thatπ? And why in that case for is better than while?
@karina said:
@stephen said:
self.point=Point(w() + self.position.w, h() - self.size.h)
Ah, I forgot that we're inside Node, not Scenei understand what lw() does, but what is lower port width? And lw() is the returns the width, if add bw(), we should get beyond the screen?
Response:
sw β screen width
bw β block width
lw β level view port width
top part and lower part , at least in this case, are the same size width. so both top and bottom parts get their size width from our bw() Block Width.
Yes we do want to add AT LEAST block width past screen width.
Video Games are Feuled by immersion. You wand the End User to feel that our Level already exists.. so they must not see the objects pop into our level. so we do this just outside the view port. same for removinghe objects. we wait till they are at least Block Width negative position if block.w < -block.w: del block.
Also in our position checks we want to compare < for removing blocks and > for adding blocks and not <= and >=. by doing this we get a 1 point buffer insuring our create and delete actions are not visible bo End User.
@karina said:
@stephen said:
self.size.w is somthing crazy like 2389488754589433357
I went to check the self.size.w, and it is 1024. What do you it is smth like thatπ? And why in that case for is better than while?
Response:
β π€π unlikely i know but just for fun... β
the value 2389488754589433357 this game is simple so this shouldnt happen. you coud see similar if you had bad execution order while using large open world type game environment...
since python has a GIL Global Interpreter Lock both the for and the whie loops are "blocking" and both can be used to achive hat you want.. The only prolem i can see making the for loop better choice here is that a while loop has the possibility of being infinit if somthing doesnt go right where the for loop has a predefined end point. insuring the game will not freeze forever do to your code withen.
---
did i cover what you were confused for these? im not sure i completey understook your questions. π
I thought of grouping the blocks but don't know how to do it.
It's quite difficult to me to formulate them now cause I don't have anything to write on and can't buy itπΏ But:
I don't know what the timing_sinodial, timing_ease in and others mean. I tried to play with them in examples but didn't see the difference, also anti-alias and its 4x multisampling
And the Brushes, so didn't implement it and MaxSizeBrush, but maybe I will when do the jumps
@Karina ill whip up a quick example that will show the diferences and ill Annotate as much as i can π hang tight
what do you mean you have nothing to write on?
@stephen a notebook or smth and I wouldn't have to look what was in the beginning and had important things in front of me
@Karina said:
@stephen a notebook or smth and I wouldn't have to look what was in the beginning and had important things in front of me
what are you using currently? and im sorry im taking so long to get back but i read overball the comments and im not sure i covered all the questions before. do you still not understand how the following works?
- w()
-update(self)
-self.dt
-self
-self.size.w
-lw()
my final example full game will include all these and more but i dont want you to throw a full script at you unless you can comprehend a good amount. most of what has been covered has been mostly linear and the full script ill feel like a spider web lol but ill annotate as much as i can.
w()
-update(self)
-self.dt
-self
-self.size.w
-lw()
This yes, here it looks quite easy.
I'm trying to write for now like I can, though it's not the best way and I get annoying bugs sometimes
What it means that it all was linear?
the full script ill feel like a spider web lol but ill annotate as much as i can.
Wow I'm scared
@stephen You said @in_background makes smth run on a dif thread. I'm not into the ui for now, but what is the dif thread?
@Karina what i mean by linear is the scripts are writen in a step by step manner. and then the rest is all focused inside the loop body. just a way i refer to simple writing techniques. where alternatively i tend write in a manner that jumps around. multiple inheritence, conroller types, delegates.. and so on.
@karina said:
@stephen You said @in_background makes smth run on a dif thread. I'm not into the ui for now, but what is the dif thread?
ui.in_background() decorator executes the following process in the main thread instead of on your current event loop's. whenever you call module level run() function from scene or class method View.Present()from ui you create a new event loop separate from Interpreters main thread. Python uses GIL (Global Interpreter Lock) that only alows one thread. you can still use multiprocessing though. for info on that check out Asynchronous programming. the reason for GIL is objC memory managment is not considered "Thread Safe".
Docs said:
ui.in_background(fn):
Call a function on the main interpreter thread. This is useful to perform long-running tasks from an action or delegate callback without blocking the UI. It can also be used for functions that donβt support being called from the main UI thread (e.g. console.alert()).
as far as you not using the ui module... you have been this whole time.. lol scene uses ui quite heavely. and you dont need to import ui separatly. by using from scene import * ui is also included. from your game just call ui. and then whatever you want from there. when you run your scene game it actually prepares the ui stuff for you and then presents a SceneView if you setup a custom View class in your game script you can create a scene.SceneView and set its SceneView.scene property to your Game Object. then instead of using run(MyScene()) you present the View which places your game in its own frame on your screen making it easy to add ui objects as your gui for ur game.
@Karina and im almost finished with the Animation/Actions demo. should be posted later this evening.
currently 5pm my time
@Karina and im almost finished with the Animation/Actions demo. should be posted later this evening.
currently 5pm my time
π
def touch_began(self, touch):
sound.play_effect('arcade:Jump_4')
self.player.texture = player_textures[3]
jumping = [A.move_by(0, 100, 0.2), A.wait(1), A.move_by(0, -100, 0.1)]
self.player.run_action(A.sequence(jumping)
I tried to make him jump but it doesn't work. I know there should be a more clever way to do that but I have no idea
@Karina I havenβt used Actions much, I prefer animating nodes myself. But theoretically, from reading the docs, your code should work (assuming your indentation is correct and your actual code doesnβt miss the closed bracket at the end)
@stephen you mean fixing the Node pos by yourself? Action should work smoother and easier to write. If it also worked here)
And why in your program you called this blocks brushes?π
I began to read about threads and sometimes don't understand what about this all, but in general understand. And for what here to use them? It encreases the speed of smth?
@Karina @Drizzel here is a demo for action timing. i intended to have much more informative and visually attractive version and ill improve it in time but for noe you can see a visual difference between each interpolation.
note: this is formated for ipad only. future versions will have formatting for other devices. i appoligise.
from scene import *
class BaseSign(SpriteNode):
def __init__(self, texture=None, tag='Sign', *args, **kwargs):
super().__init__(texture=texture, *args, **kwargs)
self.anchor_point=(0.0, 1.0)
self.position = Point(10, get_screen_size()[1]-10)
self.z_position=1
self.color='#000000'
self.size=Size(get_screen_size()[0]-20, get_screen_size()[1]-20)
self.bg=SpriteNode(
texture=None,
color='#80cdff',
position=Point(3, -3),
anchor_point=(0.0, 1.0),
size=Size(get_screen_size()[0]-26, get_screen_size()[1]-26),
parent=self)
self.sign=LabelNode(
'',
position=Point(1, 15),
z_position=3,
font=('Ubuntu Mono', 18),
parent=self.bg,
color='#000000',
anchor_point=(0.0, 1.0))
class MyScene (Scene):
def setup(self):
self.dur=5
self.moveToPos=(73, 245)
self.sign=BaseSign(parent=self, position=self.size/2)
self.sign.sign.text=self.Text()
for x in range(16):
b=SpriteNode(Texture('pzl:BallGray'),
size=Size(16, 16),
color='#00f90b',
position=Point(73, (get_screen_size()[1]-132) - 36.15*x),
z_position=9,
parent=self)
b.run_action(
Action.repeat(
Action.sequence(
Action.call(self.UpdateTime, 0.1),
Action.wait(0.5),
Action.move_to(self.moveToPos[1], b.position[1], 2, x),
Action.move_to(self.moveToPos[0], b.position[1], 2, x)),-1))
def UpdateTime(self, node, progress):
if self.speed is 1:
self.speed=0.5
else:
self.speed=1
self.sign.sign.text=self.Text()
def Text(self):
return f'''
ββββββββββββββββββββββββββ
β BUILT_IN_CONSTANT β
β βββββ¦βββββββββ¦βββββββββββ£
β 2s β 2 part β 1x speed β
β βββββ©βββββββββ©βββββββββββ£
βTIMING_LINEAR β
βββ‘ βββ’
βTIMING_EASE_IN_2 β
βββ‘ βββ’
βTIMING_EASE_IN_2 β
βββ‘ βββ’
βTIMING_EASE_OUT β
βββ‘ βββ’
βTIMING_EASE_OUT_2 β
βββ‘ βββ’
βTIMING_EASE_IN_OUT β
βββ‘ βββ’
βTIMING_SINODIAL β
βββ‘ βββ’
βTIMING_ELASTIC_OUT β
βββ‘ βββ’
βTIMING_ELASTIC_IN β
βββ‘ βββ’
βTIMING_ELASTIC_IN_OUT β
βββ‘ βββ’
βTIMING_BOUNCE_OUT β
βββ‘ βββ’
βTIMING_BOUNCE_IN β
βββ‘ βββ’
βTIMING_BOUNCE_IN_OUT β
βββ‘ βββ’
βTIMING_EASE_BACK_IN β
βββ‘ βββ’
βTIMING_EASE_BACK_OUT β
βββ‘ βββ’
βTIMING_EASE_BACK_IN_OUT β
βββ‘ βββ’
ββββββββββββββββββββββββββ'''
if __name__ == '__main__':
run(MyScene(), show_fps=True)
@Karina I think you got me mixed up with @stephen :) And yes, I do prefer to fix the nodeβs position manually.
My version of flappy bird I posted here some days ago is a good example. I used basic physics formulas to give the bird an acceleration, and then use that to calculate the birdβs speed and thus position at a given time. Then adjusting the gravity and weight parameters made the motion feel βjust rightβ (in my opinion).
Technical stuff aside, I just do it for greater control, so I can get the feeling of motions right.
@stephen looking good! I always was a little too lazy to try them all out... and Iβm not using scene much nowadays.
@Karina said:
@stephen you mean fixing the Node pos by yourself? Action should work smoother and easier to write. If it also worked here)
And why in your program you called this blocks brushes?π
i did mean changing the nodes pos manually and its prety smooth esspecially when you implement your own interpolation (the TIMING constants used with Actions).
what my main concern was that you were creating an Action Proccess for every block instead of having one Action Process for a group of blocks. this group would be the brushes i keep talking about.
in my older exampe i did refer to blocks as brushes and then later i corrected myself. in my final example (the game not the action demo and i havnt finished my version of the game yet) will have "brushes" and everything will be anotated so you its easy to understand each part.
Brush: predefined graphical structure to be instantiated multiple times. often cached for fast referencing." Example: Trees and Vilages in MineCraft..
@Karina said:
I began to read about threads and sometimes don't understand what about this all, but in general understand. And for what here to use them? It encreases the speed of smth?
I certainly donβt know everything about threads either, but hereβs my understanding of them.
The basics:
* I think of threads like... well threads, as in strings or a thin rope. And when you open a thread, the code in this thread is run separated to other threads.
-
Thus Threads allow for separate codes to run βat the same timeβ (this technically isnβt possible, and is done through some tricks so that it appears so. Thus the quotation mark. But Iβm not here to confuse you, so letβs go on)
-
Therefore you can have one section of code that (for example) has a time.sleep(100000) in it, and a thread that prints stuff in an infinite loop. Since they run in different threads, your code will still print stuff, even though thereβs a stupidly long sleep statement in it
Edit If you want some coding examples, I can write you some with comments
@Drizzel @Karina
Quick Update..
Nearly finished with the example game. I usually dont take this long but lifes been crazy lol
Done:
- EventManager
- block type classes
- GameObject class for creating individual objects
- Brush class for creating brush objects (template groups of GameObjects)
- land and sky generation
- Obsticle Gap Generation (better flow of gap hieght generation)
- Animation Class (added to GameObjects and Brushes as Instance Properties)
- Standard Obsticle Brush (objects with gap to flap/fly through)
- Connection of GameObjects, Brush Objects, Animations, EventManager and Scene Class. (pretymuch everyone can talk to everyone and all get Tick/Update calls to stay current)
TODO:
- Player class
- points score and rewards system
- Main Menu
- Settings Menu (maybe.. depends on time)
- PowerUps/Buffs/Boosters
- Game State Handle
NOTE:
@Karina did the Action timing demo help you understand the differences between each? it wasnt as informative as i like but figured it was ok givin the visual aspect
@Drizzel But in pythonista threads can't run in parallel, so it shouldn't increase the speed. So what benefits we have?
And when I put sleep, I don't want things to print
Quick Update..
Already some familiar things in it)
@Karina did the Action timing demo help you understand the differences between each? it wasnt as informative as i like but figured it was ok givin the visual aspect
@stephen Yes but it seems that all they are alike, some are nearly the same. But what the columns 2s, 2 part, 1x speed?
And how did you built this table?)
And I'm learning, most of time with my ipad, the most important that it's suitable for it
@Karina Now yes, threads may not always speed up your program. But they can keep your program responsive even though thereβs some time consuming task being done. I also sometimes use them to constantly check if a variable changed, and then trigger a function. (Thereβs better ways to do that. But hey, Iβm learning too.)
Even though this is in no way specific to Pythonista, letβs take a slight detour. Some time ago, I built a door manager for the chicken pen of my family (yeah, itβs a bit unusual). It opens and closes the door at given times, but also constantly checks a button and email for a manual overrides. Since the button needs to be checked every 0.1 seconds, but checking the email takes about 4 seconds (establishing a connection to the google servers takes some time), the button wouldnβt be checked while the code is trying to get the new email. This is solved with threads, so they get checked in parallel, not after each
Therefore the button stays responsive, even though checking mails uses up a lot of time
@Drizzel Sorry, i've not so understood what have you done. What means door manager for chicken pen? Your family has a chicken that has a pen and needs door manager??) what
But what here does the thread I got
@Karina Yeah, we have a little βchicken houseβ and I wrote a script that opens and closes the door by turning on and off a motor. But thatβs not the point :) I just needed an example to better illustrate the uses of threads
@Drizzel @Karina
First A Litle On The Thread Conversation
this comes from years experience ith event driving C# programing, but doesnt mean its correct π
Stop thinking so much about threads βΊοΈ. multiprocessing is what we do.
StackOverflow said:
What is meant by synchronous and asynchronous?
Synchronous basically means that you can only execute one thing at a time. Asynchronous means that you can execute multiple things at a time and you don't have to finish executing the current thing in order to move on to next one.
https://www.techwalla.com βΊ articles said:
Which is faster synchronous or asynchronous?
Asynchronous transfers are generally faster than synchronous transfers. This is because they do not take up time prior to the transfer to coordinate their efforts. However, because of this, more errors tend to occur in asynchronous transfers as opposed to synchronous transfers.
I know its not a great source but its not always the worst ππ
https://en.m.wikipedia.org/wiki/Asynchronous_I/O said:
In computer science, asynchronous I/O (also non-sequential I/O) is a form of input/output processing that permits ...
---
@Karina said:
@stephen Yes but it seems that all they are alike, some are nearly the same. But what the columns 2s, 2 part, 1x speed?
And how did you built this table?)
They are very similar yes but when you combine them in different ways with multiple objects you can see the way they are differnent.
this is already shown in my game example that is nearly finished. i think you will benifit alot from it. im trying to write it as clearly as i can which is why its taking so long..
the 2s 2 part 1x speed is just data not colums but i can see how i made it sem that way but its just info about the example.
2s β 2 seconds animation duration per part.
2 part β loop is 2 parts part one is
ββand part two isββ1x speed β the Scene's
Scene.speedis set to1
i put them in just to clearify settings. βΊοΈ
the lines/borders i used are Unicode from the Drawing chart. i have already included these in the Example script i modified here for Special Characters.py the comments instruct how to se it ππ€
well back to the game lol
@stephen it's ok that it takes time, I'm trying to read your and Drizzel's programs and adding things to mine
@Drizzel can you show a short example how you do animation? I have experience only with Action
@Karina
heres an example of a animation layer. i use group of sequences then stack oher groups in objects to create my deired effect. and the gam ont be production worthy just simple with my touch π but im using many different techniques for see. nearly done just couple more classes nd thn annotations and its all ya'lls
def Vibrate(self, repeat, speed, t=TIMING_LINEAR):
self.node.run_action(
a.repeat(
a.group(
a.sequence(
a.move_by( 5, 5, speed, t),
a.move_by(-5,-5, speed, t),
a.move_by(-5, 5, speed, t),
a.move_by( 5,-5, speed, t)),
a.sequence(
a.scale_y_by( 0.1, speed, t),
a.scale_y_by(-0.1, speed, t),
a.scale_y_by( 0.1, speed, t),
a.scale_y_by(-0.1, speed, t))
),repeat))
def player_flies(self):
g = gravity()
speed = 1000
if abs(g.x) > 0.05:
y = self.player.position.y
self.player.position.y = min(sh(), max(41, y + speed*g.y))
print(self.player.position.y)
I tried to move him with gravity but also doesn't work, like player.position.y is unchangeable or = doesn't work
Don't know what to doπ
@Karina said:
def player_flies(self): g = gravity() speed = 1000 if abs(g.x) > 0.05: y = self.player.position.y self.player.position.y = min(sh(), max(41, y + speed*g.y)) print(self.player.position.y)I tried to move him with gravity but also doesn't work, like player.position.y is unchangeable or = doesn't work
Don't know what to doπ
try changing min(sh(), max(41, y + speed*g.y)) to
min(sh(), max(41, self.player.position.y + speed*g.y))
that shouldnt change anything but just a debugging step..
then try using:
def player_flies(self, speed=100,):
if gravity()[1] > 0.5:
x, y = self.player.position
self.player.position = Point(x, (y + speed) * gravity()[1])
print(self.player.position[1])
from my knowledge you cannot set position.y you have to set the whole point.
also if you want the player to move upwards by tilting the top of device down. you must multiply by -1 gravity()[1] * -1 that way your output is positive. also the x, y, z properties of gravity are real numbers 0.0-1.0 just incase you didnt know. π
Also my example game is just about ready. just doing some gui stuff and Annotations.
@stephen actually I want it to jump when I touch, but I couldn't do this. Now I get what was the problem but didn't fix it
I always forget to use the Point for position, can you show why it's better?
@stephen i've read your code with brushes, got it but have some little questions
1
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, ])
#what means the , in the end of the list? And how we add base blocks of next brushes to the list?
2, 3
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([])
#But the [] is already list
self.scrollSpeed=40
for x in range(int((w()*128)/64)):
#so it's w()*2? Why 2?
self.brushes.append(Stone(self, x))
@stephen said:
Vibrate(self, repeat, speed, t=TIMING_LINEAR):
self.node.run_action(
a.repeat(
a.group(
a.sequence(
a.move_by( 5, 5, speed, t),
a.move_by(-5,-5, speed, t),
a.move_by(-5, 5, speed, t),
a.move_by( 5,-5, speed, t)),
a.sequence(
a.scale_y_by( 0.1, speed, t),
a.scale_y_by(-0.1, speed, t),
a.scale_y_by( 0.1, speed, t),
a.scale_y_by(-0.1, speed, t))
),repeat))
I think I have a problem in my action that after moving up there's down, so it does nothing. But here you do itπ³
@Karina said:
@stephen i've read your code with brushes, got it but have some little questions
1
```
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, ])
#what means the , in the end of the list? And how we add base blocks of next brushes to the list?```
2, 3
```
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([])
#But the [] is already list
self.scrollSpeed=40for x in range(int((w()*128)/64)): #so it's w()*2? Why 2? self.brushes.append(Stone(self, x))```
that comma is optional but it just indicates that you intend on adding more to the list. just a habbit.
that brush example is not good. my game example will show u MANY things throught and is currently at 1400 lines without comments. i should have it posted in the next 8 hours. this script im making will show u actual brushes.. i would ignore the old one.
and to add bade block to that list just do self.blocks.append(block)
@Karina said:
@stephen actually I want it to jump when I touch, but I couldn't do this. Now I get what was the problem but didn't fix it
I always forget to use the Point for position, can you show why it's better?
jump on tap is prety easy. in your touch_began trigger somthing like the following for a very simple way.
def touch_began(self, touch):
self.player.run_action(
a.sequence(
a.move_by(128, 64, 0.5, TIMING_LINEAR),
a.wait(0.1),
a.move_by(128, 128, 2, TIMING_LINEAR)), 'tag:player-jump')
this should give an abrupt leap then more of a glide back down. the wait is just a buffer for junt in case and use whatever timing that looks best for ur needs. this is not desinged for uneven ground. u need collision checks for uneven and i show that in my new exmple
@Karina said:
def player_flies(self): g = gravity() speed = 1000 if abs(g.x) > 0.05: y = self.player.position.y self.player.position.y = min(sh(), max(41, y + speed*g.y)) print(self.player.position.y)I tried to move him with gravity but also doesn't work, like player.position.y is unchangeable or = doesn't work
Don't know what to doπ
in my earlierpost i show that you must set the hole position you cannot set just x or y
@Karina said:
@stephen said:
Vibrate(self, repeat, speed, t=TIMING_LINEAR):
self.node.run_action(
a.repeat(
a.group(
a.sequence(
a.move_by( 5, 5, speed, t),
a.move_by(-5,-5, speed, t),
a.move_by(-5, 5, speed, t),
a.move_by( 5,-5, speed, t)),
a.sequence(
a.scale_y_by( 0.1, speed, t),
a.scale_y_by(-0.1, speed, t),
a.scale_y_by( 0.1, speed, t),
a.scale_y_by(-0.1, speed, t))
),repeat))
I think I have a problem in my action that after moving up there's down, so it does nothing. But here you do itπ³
this was an example of doing a vibration effect. so it needs to move even amounts in directions because its doesnt move anywhere. just "shakes"
was mainly meant to show you a repeated group with sequence sections for action structures
def touch_began(self, touch):
self.player.run_action(
a.sequence(
a.move_by(128, 64, 0.5, TIMING_LINEAR),
a.wait(0.1),
a.move_by(128, 128, 2, TIMING_LINEAR)), 'tag:player-jump')
But it means he moves on 128 forward, cause move_by(dx, dy, duration, timing_mode). And after wait he should move Dow, so dy with minus? And what is 'tag:player-jump'?
my game example will show u MANY things throught and is currently at 1400 lines
@stephen this is *10 more than anything I have ever readπ³ Don't worry, you can't show too little things in itπ
I should be an easy game, I thought I the beginning
@Karina ill be posting the example shortly
@Karina said:
def touch_began(self, touch): self.player.run_action( a.sequence( a.move_by(128, 64, 0.5, TIMING_LINEAR), a.wait(0.1), a.move_by(128, 128, 2, TIMING_LINEAR)), 'tag:player-jump')But it means he moves on 128 forward, cause move_by(dx, dy, duration, timing_mode). And after wait he should move Dow, so dy with minus? And what is 'tag:player-jump'?
yes your correct i made a boo boo lol i didnt test i just wrote
def touch_began(self, touch):
self.player.run_action(
a.sequence(
a.move_by(128, 64, 0.5, TIMING_LINEAR),
a.wait(0.1),
a.move_by(-128, -128, 2, TIMING_LINEAR)), 'tag:player-jump')
@stephen still nothing. I just did copy paste for not to do mistakes. Maybe it's somewhere else in the code
from scene import *
import sound
import random
import time
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.0 if so() == 1 else 768.0
def lh(): return 1024.0 if so() == 2 else 768.0
A = Action()
player_textures = [Texture('plf:AlienBeige_walk1'),
Texture('plf:AlienBeige_walk2'), Texture('plf:AlienBeige_hit'), Texture('plf:AlienBeige_jump'), Texture('plf:AlienBeige_stand')]
def GroundBlock(parent):
return SpriteNode('plf:Ground_Grass', parent=parent)
def ColumnBlock(parent, x, y):
return SpriteNode('plc:Brown_Block', parent=parent, anchor_point = (0.5, 0), position = Point(x, y))
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 = []
self.moveTo = (220, 120)
self.add_column()
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', position = Point(x, 30))
higher_tile = SpriteNode('plf:Ground_GrassCenter', position = Point(x, 738))
x += bw() - 2
ground.add_child(lower_tile)
ground.add_child(higher_tile)
self.player = SpriteNode('plf:AlienBeige_front', parent=self)
self.player.position = (40, 120)
self.play_effect = 0
self.game_over = False
def update(self):
if self.t > 1:
self.player_runs()
self.time_passed += self.dt
if self.time_passed >= 1.5:
self.add_column()
self.time_passed = 0
self.column_moves()
self.player_hit()
if self.game_over == True and self.player.position.y < 30:
self.player.remove_from_parent()
def touch_began(self, touch):
#self.player_jumps()
self.player.run_action(
A.sequence(
A.move_by(128, 64, 0.5, TIMING_LINEAR),
A.wait(0.1),
A.move_by(-128, -128, 2, TIMING_LINEAR)), 'tag:player-jump')
def new_game(self):
A.wait(2)
for i in self.columns:
i.remove_from_parent()
self.player.texture = player_textures[4]
self.player.position = (40, 120)
def add_column(self):
lower = random.randint(0, 360) // bw()
#building the lower part
for i in range(lower):
self.columns.append(ColumnBlock(self, self.size.w + bw(), i*64 + 55))
#building the higher part
for i in range(9 - lower):
self.columns.append(ColumnBlock(self, self.size.w + bw(), (self.size.h - 100) - i*64))
def column_moves(self):
action = A.move_by(-self.size.w - bw(), 0, 0.7, TIMING_SINODIAL)
for i in self.columns:
i.run_action(action)
def player_runs(self):
self.player.x_scale = 1
walking_sounds = ['rpg:Footstep04', 'rpg:Footstep05']
if self.player.position.x <= 200:
step = int(self.player.position.x/5) % 2
self.player.texture = player_textures[step]
action = A.move_by(20, 0, 1.5)
self.player.run_action(action)
self.play_effect += 1
if self.play_effect % 30 == 0:
sound.play_effect(walking_sounds[step])
def player_hit(self):
player_hitbox = Rect(self.player.position.x - 10, self.player.position.y + 10, 10, 10)
for c in self.columns:
if c.frame.intersects(player_hitbox):
self.player.texture = player_textures[2]
self.player.run_action(A.move_by(0, -200, 0.2))
sound.play_effect('arcade:Hit_2')
self.game_over = True
def player_jumps(self):
self.player.run_action(
A.sequence(
A.move_by(128, 64, 0.5, TIMING_LINEAR),
A.wait(0.1),
A.move_by(-128, -128, 2, TIMING_LINEAR)), 'tag:player-jump')
run(Game())
@Karina i added isGrounded and adjusted the Actions. it needs some fine tuning but he jumps. im finalizing my game now so after a few touchups ill postit here
from scene import *
import sound
import random
import time
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.0 if so() == 1 else 768.0
def lh(): return 1024.0 if so() == 2 else 768.0
A = Action()
player_textures = [Texture('plf:AlienBeige_walk1'),
Texture('plf:AlienBeige_walk2'), Texture('plf:AlienBeige_hit'), Texture('plf:AlienBeige_jump'), Texture('plf:AlienBeige_stand')]
def GroundBlock(parent):
return SpriteNode('plf:Ground_Grass', parent=parent)
def ColumnBlock(parent, x, y):
return SpriteNode('plc:Brown_Block', parent=parent, anchor_point = (0.5, 0), position = Point(x, y))
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 = []
self.moveTo = (220, 120)
self.add_column()
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', position = Point(x, 30))
higher_tile = SpriteNode('plf:Ground_GrassCenter', position = Point(x, 738))
x += bw() - 2
ground.add_child(lower_tile)
ground.add_child(higher_tile)
self.player = SpriteNode('plf:AlienBeige_front', parent=self)
self.player.position = (40, 120)
self.play_effect = 0
self.game_over = False
self.isGrounded=True
def update(self):
if self.t > 1:
self.player_runs()
self.time_passed += self.dt
if self.time_passed >= 1.5:
self.add_column()
self.time_passed = 0
self.column_moves()
self.player_hit()
if self.game_over == True and self.player.position.y < 30:
self.player.remove_from_parent()
def touch_began(self, touch):
self.player_jumps()
def toggle_Grounded(self):
self.isGrounded = not self.isGrounded
def new_game(self):
A.wait(2)
for i in self.columns:
i.remove_from_parent()
self.player.texture = player_textures[4]
self.player.position = (40, 120)
def add_column(self):
lower = random.randint(0, 360) // bw()
#building the lower part
for i in range(lower):
self.columns.append(ColumnBlock(self, self.size.w + bw(), i*64 + 55))
#building the higher part
for i in range(9 - lower):
self.columns.append(ColumnBlock(self, self.size.w + bw(), (self.size.h - 100) - i*64))
def column_moves(self):
action = A.move_by(-self.size.w - bw(), 0, 0.9, TIMING_SINODIAL)
for i in self.columns:
i.run_action(action)
def player_runs(self):
self.player.x_scale = 1
walking_sounds = ['rpg:Footstep04', 'rpg:Footstep05']
if self.player.position.x <= 200 and self.isGrounded:
step = int(self.player.position.x/5) % 2
self.player.texture = player_textures[step]
action = A.move_by(20, 0, 0.5)
#self.player.run_action(action)
self.play_effect += 1
if self.play_effect % 30 == 0:
sound.play_effect(walking_sounds[step])
def player_hit(self):
player_hitbox = Rect(self.player.position.x - 10, self.player.position.y + 10, 10, 10)
for c in self.columns:
if c.frame.intersects(player_hitbox):
self.player.texture = player_textures[2]
self.player.run_action(A.move_by(0, -200, 0.2))
sound.play_effect('arcade:Hit_2')
self.game_over = True
def player_jumps(self):
self.player.run_action(
A.sequence(
A.move_by(32, 128, 0.5, TIMING_LINEAR),
A.move_to(self.player.position[0]+128, 120, 0.5, TIMING_LINEAR)))
run(Game())
here is the game lol made new thread fo it
@stephen thank you, I've began to read it
@Karina Awesome if you have any questions please post on the new thread π
@Karina also "brushes" are properly used in the example so hopfully you see the diference