在ipad上写蛇(pythonista)

...或者如何使用ipad消磨时间,仅此而已...

你好

你在说什么


不幸的是,平板电脑尚未取代计算机。 但是乘车/飞行至关重要。 因此,我寻找了ipad底下的东西,实际上今天我将在Pythonista上进行游戏。

我们该怎么办?


最简单的程序,例如晶体(是的,是的,就是您在地铁上玩的程序)。 俄罗斯方块,蛇,填充-任何新手,只要有一点了解,都将在30分钟内写出它们。 在过场动画下-屏幕截图,教程,代码。

以下是我搞砸了的一些屏幕截图:

许多截图











免责声明
本文不仅专门针对初学者(但了解python),并且不允许您在十分钟内或任何现成的应用程序中创建坦克世界,但从编程宗教的角度出发,作者也不保证绝对美观且正确的代码(尽管他尝试过) 。 而且pythonista的示例和文档中也有一些东西被盗。

所有代码将在末尾给出。

了解pythonista中的图形


汇入
from scene import * import random 


立即创建场景:

 class Game(Scene): def setup(self): self.background_color = "green" run(Game(), LANDSCAPE) 

好吧,让我们立即开始。 您应该有一个绿屏。 让我们做一些很酷的事情,方法是将更新方法(系统本身调用)添加到Game类中,并为其更改背景颜色。

 class Game(Scene): #    def update(self): self.background_color = (1.0, 1.0, (math.sin(self.t) + 1) / 2) 

现在,我们的屏幕从黄色平滑过渡到白色,反之亦然。



现在创建一些对象。 我们还在setup方法中创建它:

 class Game(Scene): def setup(self): self.background_color = "white" mypath = ui.Path.rect(0, 0, 50, 50) self.obj = ShapeNode(mypath) self.obj.color = "purple" #      html,  #FF00FF.   tuple,   (1.0, 0.0, 1.0).       alpha,    self.add_child(self.obj) def update(self): self.obj.position = (500 + 200 * math.sin(self.t), 500 + 200 * math.cos(self.t)) 

我们设置线(mypath),在其上创建一个ShapeNode,将其指向一种颜色,然后指定一个父对象(本质上是相同的-在创建时指定一个父对象,即ShapeNode(* ...,parent = self)或self.add_child (obj))。

好吧,在Game.update()中,我们更改对象(元组)的位置,它以像素为单位,从左下角开始计数。
请注意,我们不需要重新绘制场景(尽管有可能)。 其父作为场景的对象和节点(或其某些子对象)将自己重新绘制
我们在本节中要介绍的最后一件事是touch_began(以及touch_moved和touch_ended)。 很容易猜到,该方法可以捕获屏幕上的点击。 让我们尝试一下:

 class Game(Scene): def touch_began(self, touch): mypath = ui.Path.oval(0, 0, 50, 50) obj = ShapeNode(mypath) obj.color = (0.5, 0.5, 1.0) self.add_child(obj) obj.position = touch.location 



每次您在屏幕上单击时,我们都会创建一个圆圈,单击的位置是touch.location。

准备写一条蛇


游戏机制
蛇是正方形的阵列,当头部移动时-第二块移动到第一个,第三个移动到第二个,依此类推。为找出头部与尾巴的交点,我们将其与每条尾巴进行比较

我们删除所有书面代码,因为我们想或多或少地做到美观(但是,当然,我们会骑自行车)。

首先,让我们创建PhyObj类:

 class PhyObj: def __init__(self, path, color, parent): self.graph_obj = ShapeNode(path, parent=parent) self.parent = parent self.graph_obj.color = color def setpos(self, x, y): self.graph_obj.position = (x, y) def getpos(self): return self.graph_obj.position def move(self, x, y): self.graph_obj.position += (x, y) 

我认为这里的一切都很微不足道。 在类本身内部,我们创建了一个节点,并描述了一些使我们的代码更具可读性的方法。

holivary
就我个人而言,我更喜欢先创建具有许多重复方法和属性的低级类,但随后高级类中的代码将变得非常漂亮且易读。

PhyObj是我们游戏中最低级别的对象,实际上它是抽象的物理对象。

蛇描述


现在,我们需要描述这条蛇,由于它是由碎片组成的,因此我们将首先描述一条:

 class Tile(PhyObj): def __init__(self, parent, size, margin=4): super().__init__(ui.Path.rect(0, 0, size[0] - margin, size[1] - margin), "#66FF66", parent) def die(self): self.graph_obj.color = "red" 

在构造函数中,我们调用类的父方法,并给我们自己指定形状和颜色。 需要留有边距,以使正方形不会粘在一起并形成某种网格。

 class Game(Scene): def setup(self): self.tile = Tile(self, (40, 40)) self.tile.setpos(100, 100) 

结果应该是:



但是例如,为什么我们需要保证金:

 class Game(Scene): def setup(self): tile1 = Tile(self, (40, 40)) tile1.setpos(100, 100) tile2 = Tile(self, (40, 40)) tile2.setpos(140, 100) 



好了,现在您需要从这些碎片上粘蛇。 我们需要一个初始化方法和一个移动方法。

首先,创建初始化:

 class Snake: def __init__(self, length, width, initpos, parent): self.width = width #     self.tiles = [Tile(parent, (width, width)) for i in range(length)] #        for i, tile in enumerate(self.tiles): tile.setpos(initpos[0] + i * self.width, initpos[1]) #        

让我们尝试立即绘制它:

 class Game(Scene): def setup(self): self.snake = Snake(10, 40, (200, 200), self) 



好吧,添加移动方法。

 class Snake: def move(self, x, y): for i in range(len(self.tiles) - 1, 0, -1): self.tiles[i].setpos(*self.tiles[i - 1].getpos()) self.tiles[0].move(x * self.width, y * self.width) 

首先,我们将最后一个移到倒数第二个,然后将倒数第二个移到倒数第二个,然后将第二个移到第一个。 以及第一个(x,y)。

实际上,我们的蛇直线移动得很好。 让我们尝试:

 class Game(self): # <...> def update(self): self.snake.move(0, 1) 

如果您设法看到,那么她应该爬行了。 事实是,更新被调用得非常频繁(顺便说一下,可以选择以相同的间隔),因此我们需要考虑自上次调用以来已经经过了多少时间,并等待直到其“累积”了足够的时间。

简而言之,我们这样做:

 class Game(Scene): def time_reset(self): self.last_time = self.t def time_gone(self, t): if self.t - self.last_time > t: res = True self.time_reset() else: res = False return res def setup(self): self.snake = Snake(10, 40, (200, 200), self) self.time_reset() def update(self): if self.time_gone(0.3): self.snake.move(0, 1) 

如果经过的时间超过t,则time_gone返回True。 现在,蛇将每0.3秒移动一次。 奏效了吗?



管理学


现在您需要进行控制,即在所有四个方向上转弯:



 class Game(Scene): # <...> def setup(self): # <...> self.dir = (0, 1) #     def update(self): if self.time_gone(0.3): self.snake.move(*self.dir) 

现在,我们需要进行touch_began处理以了解用户插入的区域。 实际上,结果并没有我想的那么有趣,因此您可以在此处简单地复制:

 class Game(Scene): # <...> def touch_began(self, touch): ws = touch.location[0] / self.size.w hs = touch.location[1] / self.size.h aws = 1 - ws if ws > hs and aws > hs: self.dir = (0, -1) elif ws > hs and aws <= hs: self.dir = (1, 0) elif ws <= hs and aws > hs: self.dir = (-1, 0) else: self.dir = (0, 1) 

好吧,现在尝试转身



制定了主要机制,仍然需要检查碰撞和苹果。

尾巴碰撞


让我们开始检查并向蛇添加find_collisions方法

 class Snake: # <...> def find_collisions(self): for i in range(1, len(self.tiles)): if self.tiles[i].getpos() == self.tiles[0].getpos(): return self.tiles[i], self.tiles[0] return False 

现在我们可以获得一对相交的细胞。 我想将它们涂成红色,将die方法添加到Tile中:

 class Tile(PhyObj): # <...> def die(self): self.graph_obj.color = "red" 

添加检查以更新和更改设置:

 class Game(Scene): # <...> def setup(self): self.snake = Snake(30, 40, (200, 200), self) #   self.time_reset() self.dir = (0, 1) self.game_on = True #   ? def update(self): if not self.game_on: #  ,  return col = self.snake.find_collisions() #  ? if col: for tile in col: tile.die() #     self.game_on = False #   if self.time_gone(0.3): self.snake.move(*self.dir) 

我怎么了:



它仍然是用来做苹果的。

伸长率和苹果


我们将加长蛇,并使它看起来更漂亮,将根据后两个添加新的链接,即:



将方法添加到蛇:

 class Snake: # <...> def find_dir(self, x1, y1, x2, y2): if x1 == x2 and y1 > y2: return (0, 1) elif x1 == x2 and y1 < y2: return (0, -1) elif y1 == y2 and x1 > x2: return (1, 0) elif y1 == y2 and x1 < x2: return (-1, 0) else: assert False, "Error!" def append(self): if len(self.tiles) > 1: lastdir = self.find_dir(*self.tiles[-1].getpos(), *self.tiles[-2].getpos()) else: lastdir = (-self.parent.dir[0], -self.parent.dir[1]) self.tiles.append(Tile(self.parent, (self.width, self.width))) x_prev, y_prev = self.tiles[-2].getpos() self.tiles[-1].setpos(x_prev + lastdir[0] * self.width, y_prev + lastdir[1] * self.width) 

find_dir查找女主人公的尾巴尖的方向。 追加,很容易猜到,添加了一个单元格。 在Game中添加另一个snake_lengthen方法:

 class Game(Scene): # <...> def snake_lengthen(self): self.snake.append() self.time_reset() 

最后一行是需要的,以便蛇稍等一会儿,并且用户设法看到添加了那条。

要确定某条蛇是否与某条线相交,请向该条蛇添加相交方法。

 class Snake: # <...> def getpos(self): return self.tiles[0].getpos() def intersect(self, x, y): return self.getpos() == (x, y) 

万岁,它仍然只是创建一个苹果。 实际上,我们一口气描述了苹果:

 class Apple(PhyObj): def __init__(self, width, size, parent): super().__init__(ui.Path.oval(0, 0, size[0], size[1]), "#55AAFF", parent) self.parent = parent self.width = width self.dislocate() def dislocate(self): a = random.randint(2, int(self.parent.size.w / self.width) - 2) b = random.randint(2, int(self.parent.size.h / self.width) - 2) self.setpos(a * self.width, b * self.width) 

需要这种奇怪的随机性来使我们的靶心适应网格。 这样就不必寻找枪口和苹果之间的距离并比较其pyre-pyr。 就在ifas上。 让我们去更新并在此函数的末尾添加非常简单的行:

 class Game(Scene): # <...> def setup(self): self.apple = Apple(40, (50, 50), self) # 40 -  ,       Snake() # <...> def update(self): # <...> if self.snake.intersect(*self.apple.getpos()): self.snake_lengthen() self.apple.dislocate() 

好吧,一切似乎都发生了,现在如果蛇撞到苹果,蛇会伸长,而撞到苹果则死。



红利


您可以制作音效:

 import sound class Game(Scene): # <...> def snake_lengthen(self): self.snake.append() self.time_reset() sound.play_effect('arcade:Powerup_1', 0.25, 0.8) 

进行平滑运动:

 class Game(Scene): # <...> def setup(self): self.game_on = False self.GLOBAL_TIMING = 0.2 self.GLOBAL_WIDTH = 40 self.apple = Apple(self.GLOBAL_WIDTH, (50, 50), self) self.snake = Snake(10, self.GLOBAL_WIDTH, (200, 200), self) self.time_reset() self.dir = (0, 1) self.game_on = True class Snake: # <...> def move(self, x, y): for i in range(len(self.tiles) - 1, 0, -1): self.tiles[i].setpos(*self.tiles[i - 1].getpos(), self.parent.GLOBAL_TIMING) self.tiles[0].move(x * self.width, y * self.width, self.parent.GLOBAL_TIMING) class PhyObj: def __init__(self, path, color, parent): self.graph_obj = ShapeNode(path, parent=parent) self.parent = parent self.graph_obj.color = color self.pos = self.graph_obj.position def setpos(self, x, y, t=0.0): self.pos = (x, y) self.graph_obj.run_action(Action.move_to(x, y, t)) #    x, y    t def getpos(self): return self.pos def move(self, x, y, t=0.0): self.pos = (self.pos[0] + x, self.pos[1] + y) self.graph_obj.run_action(Action.move_by(x, y, t)) 

换句话说,我们更改了位置PhyObj的逻辑。 以前,我们专注于图形元素的位置,现在有一个单独的逻辑位置字段(即用于游戏逻辑的字段),并且图形元素的位置现在是自由的,可以以自己的方式更改。 即,使用“动作”,我们为她留出了并行流,并在其中进行移动。

这样一条光滑的蛇竟然是:



最后,加上蛇的长度的标签:

 class Game(Scene): # <...> def setup(self): self.game_on = False self.GLOBAL_TIMING = 0.2 self.GLOBAL_WIDTH = 40 self.apple = Apple(self.GLOBAL_WIDTH, (50, 50), self) self.snake = Snake(30, self.GLOBAL_WIDTH, (200, 200), self) self.time_reset() self.dir = (0, 1) self.label = LabelNode("", font=("Chalkduster", 20), parent=self, position=(self.size.w / 2, self.size.h - 100)) #    self.update_labels() self.game_on = True def update_labels(self): self.label.text = "Length: " + str(len(self.snake.tiles)) def update(self): if not self.game_on: return col = self.snake.find_collisions() if col: for tile in col: tile.die() self.game_on = False if self.time_gone(self.GLOBAL_TIMING): self.snake.move(*self.dir) if self.snake.intersect(*self.apple.getpos()): self.snake_lengthen() self.apple.dislocate() self.update_labels() #  



朋友们,谢谢您的关注! 如果不清楚,请询问。 而且,如果这很有趣-我会继续讲,但仍有一些要说的(但是本文已经相当长了)。

所有蛇码
 from scene import * import random import math import sound class PhyObj: def __init__(self, path, color, parent): self.graph_obj = ShapeNode(path, parent=parent) self.parent = parent self.graph_obj.color = color self.pos = self.graph_obj.position def setpos(self, x, y, t=0.0): self.pos = (x, y) self.graph_obj.run_action(Action.move_to(x, y, t)) def getpos(self): return self.pos def move(self, x, y, t=0.0): self.pos = (self.pos[0] + x, self.pos[1] + y) self.graph_obj.run_action(Action.move_by(x, y, t)) class Tile(PhyObj): def __init__(self, parent, size, margin=4): super().__init__(ui.Path.rect(0, 0, size[0] - margin, size[1] - margin), "#66FF66", parent) def die(self): self.graph_obj.color = "red" class Snake: def __init__(self, length, width, initpos, parent): self.width = width self.tiles = [Tile(parent, (width, width)) for i in range(length)] for i, tile in enumerate(self.tiles): tile.setpos(initpos[0] + i * self.width, initpos[1]) self.parent = parent def move(self, x, y): for i in range(len(self.tiles) - 1, 0, -1): self.tiles[i].setpos(*self.tiles[i - 1].getpos(), self.parent.GLOBAL_TIMING) self.tiles[0].move(x * self.width, y * self.width, self.parent.GLOBAL_TIMING) def find_collisions(self): for i in range(1, len(self.tiles)): if self.tiles[i].getpos() == self.tiles[0].getpos(): return self.tiles[i], self.tiles[0] return False def find_dir(self, x1, y1, x2, y2): if x1 == x2 and y1 > y2: return (0, 1) elif x1 == x2 and y1 < y2: return (0, -1) elif y1 == y2 and x1 > x2: return (1, 0) elif y1 == y2 and x1 < x2: return (-1, 0) else: assert False, "Error!" def append(self): if len(self.tiles) > 1: lastdir = self.find_dir(*self.tiles[-1].getpos(), *self.tiles[-2].getpos()) else: lastdir = (-self.parent.dir[0], -self.parent.dir[1]) self.tiles.append(Tile(self.parent, (self.width, self.width))) x_prev, y_prev = self.tiles[-2].getpos() self.tiles[-1].setpos(x_prev + lastdir[0] * self.width, y_prev + lastdir[1] * self.width) def getpos(self): return self.tiles[0].getpos() def intersect(self, x, y): return self.getpos() == (x, y) class Apple(PhyObj): def __init__(self, width, size, parent): super().__init__(ui.Path.oval(0, 0, size[0], size[1]), "#55AAFF", parent) self.parent = parent self.width = width self.dislocate() def dislocate(self): a = random.randint(2, int(self.parent.size.w / self.width) - 2) b = random.randint(2, int(self.parent.size.h / self.width) - 2) self.setpos(a * self.width, b * self.width) class Game(Scene): def snake_lengthen(self): self.snake.append() self.time_reset() sound.play_effect('arcade:Powerup_1', 0.25, 0.8) def time_reset(self): self.last_time = self.t def time_gone(self, t): if self.t - self.last_time > t: res = True self.time_reset() else: res = False return res def setup(self): self.game_on = False self.GLOBAL_TIMING = 0.2 self.GLOBAL_WIDTH = 40 self.apple = Apple(self.GLOBAL_WIDTH, (50, 50), self) self.snake = Snake(30, self.GLOBAL_WIDTH, (200, 200), self) self.time_reset() self.dir = (0, 1) self.label = LabelNode("", font=("Chalkduster", 20), parent=self, position=(self.size.w / 2, self.size.h - 100)) self.update_labels() self.game_on = True def update_labels(self): self.label.text = "Length: " + str(len(self.snake.tiles)) def update(self): if not self.game_on: return col = self.snake.find_collisions() if col: for tile in col: tile.die() self.game_on = False if self.time_gone(self.GLOBAL_TIMING): self.snake.move(*self.dir) if self.snake.intersect(*self.apple.getpos()): self.snake_lengthen() self.apple.dislocate() self.update_labels() def touch_began(self, touch): ws = touch.location[0] / self.size.w hs = touch.location[1] / self.size.h aws = 1 - ws if ws > hs and aws > hs: self.dir = (0, -1) elif ws > hs and aws <= hs: self.dir = (1, 0) elif ws <= hs and aws > hs: self.dir = (-1, 0) else: self.dir = (0, 1) run(Game(), LANDSCAPE) 


水晶代码WhiteBlackGoose版
有趣的是,在完成之后,我在pythonista本身的示例中发现了非常相似的东西。 但我还有更多功能:)

 from scene import * from math import pi from random import uniform as rnd, choice, randint import sys import random A = Action sys.setrecursionlimit(1000000) colors = ['pzl:Green5', "pzl:Red5", "pzl:Blue5"] + ["pzl:Purple5", "pzl:Button2"] + ["plf:Item_CoinGold"] global inited inited = False class Explosion (Node): def __init__(self, brick, *args, **kwargs): Node.__init__(self, *args, **kwargs) self.position = brick.position for dx, dy in ((-1, -1), (1, -1), (-1, 1), (1, 1)): p = SpriteNode(brick.texture, scale=0.5, parent=self) p.position = brick.size.w/4 * dx, brick.size.h/4 * dy p.size = brick.size d = 0.6 r = 30 p.run_action(A.move_to(rnd(-r, r), rnd(-r, r), d)) p.run_action(A.scale_to(0, d)) p.run_action(A.rotate_to(rnd(-pi/2, pi/2), d)) self.run_action(A.sequence(A.wait(d), A.remove())) class Brick (SpriteNode): def __init__(self, brick_type, *args, **kwargs): img = colors[brick_type] SpriteNode.__init__(self, img, *args, **kwargs) self.brick_type = brick_type self.is_on = True self.lf = True self.enabled = True def destroy(self): self.remove_from_parent() self.is_on = False def mark(self): self.lf = False def demark(self): self.lf = True class Game(Scene): def brickgetpos(self, i, j): return (self.Woff + j * self.W, self.Hoff + i * self.H) def brick(self, ty, i, j): b = Brick(ty, size=(self.W, self.H), position=self.brickgetpos(i, j), parent=self.game_node) b.rotation = random.random() return b def random_brick_type(self): if random.random() < 0.992: return random.randint(0, 3) else: if random.random() < 0.8: return 5 else: return 4 def setup(self): FONT = ('Chalkduster', 20) self.score_label = LabelNode('Score: 0', font=FONT, position=(self.size.w/2-100, self.size.h-40), parent=self) self.score = 0 self.last_score_label = LabelNode('Delta: +0', font=FONT, position=(self.size.w/2-300, self.size.h-40), parent=self) self.last_score = 0 #self.avg_label = LabelNode('Speed: +0/s', font=FONT, position=(self.size.w/2+100, self.size.h-40), parent=self) #self.max_label = LabelNode('Peak: +0/s', font=FONT, position=(self.size.w/2+300, self.size.h-40), parent=self) #self.max_speed = 0 self.game_time = 120 self.timel = LabelNode('Time: ' + str(self.game_time) + "s", font=FONT, position=(self.size.w/2+300, self.size.h-40), parent=self) self.gems = [0 for i in colors] self.effect_node = EffectNode(parent=self) self.game_node = Node(parent=self.effect_node) self.l = [0 for i in colors] self.lt = [0 for i in colors] for i in range(len(colors)): R = 50 if i == 6 else 35 self.l[i] = Brick(i, size=(R, R), position=(40, self.size.h-100-i*40), parent=self.game_node) self.lt[i] = LabelNode(": 0", font=FONT, position=(self.l[i].position[0] + 40, self.l[i].position[1]), parent=self) self.WB = 30 self.HB = 30 self.W = 900 // self.WB self.H = 900 // self.HB self.colcount = 4 self.Woff = (int(self.size.w) - self.W * self.WB + self.W) // 2 self.Hoff = self.H + 10 self.net = [[self.brick(self.random_brick_type(), i, j) for i in range(self.HB)] for j in range(self.WB)] #self.touch_moved = self.touch_began self.start_time = self.t self.game_on = True global inited inited = True def demark(self): for bricks in self.net: for brick in bricks: brick.demark() def howfar(self, x, y): alt = 0 for i in range(y): if not self.net[x][i].is_on: alt += 1 return alt def update(self): global inited if not inited: return self.game_on = self.t - self.start_time < self.game_time if self.game_on: self.timel.text = "Time: " + str(round(self.game_time - (self.t - self.start_time))) + "s" else: self.timel.text = "Game over" #if speed > self.max_speed: # self.max_speed = speed # self.max_label.text = "Peak: +" + str(round(self.max_speed)) + "/s" def gravity(self, x, y): alt = self.howfar(x, y) if alt == 0: return self.net[x][y].destroy() self.net[x][y - alt] = self.brick(self.net[x][y].brick_type, y, x) self.net[x][y - alt].position = self.net[x][y].position self.net[x][y - alt].rotation = self.net[x][y].rotation self.net[x][y - alt].enabled = False self.net[x][y - alt].run_action(A.sequence(A.move_to(*self.brickgetpos(y - alt, x), 0.2 * alt ** 0.5, TIMING_EASE_IN_2), A.call(lambda: self.enable_cell(x, y - alt)))) def enable_cell(self, x, y): self.net[x][y].enabled = True def fall(self): for x in range(self.WB): for y in range(self.HB): if self.net[x][y].is_on: self.gravity(x, y) def update_scores(self): self.score += self.last_score self.score_label.text = "Score: " + str(self.score) self.last_score_label.text = "Delta: +" + str(self.last_score) self.last_score = 0 def update_cells(self): for i in range(self.WB): for j in range(self.HB): if not self.net[i][j].is_on: self.net[i][j] = self.brick(self.random_brick_type(), j + self.HB, i) self.net[i][j].enabled = True self.net[i][j].run_action(A.sequence(A.move_to(*self.brickgetpos(j, i), 0.2 * self.HB ** 0.5, TIMING_EASE_IN_2), A.call(lambda: self.enable_cell(i, j)))) def inbounds(self, x, y): return (x >= 0) and (y >= 0) and (x < self.WB) and (y < self.HB) def bomb(self, x, y, radius): score = 0 bc = 0 for i in range(round(4 * radius ** 2)): rad = random.random() * radius ang = random.random() * 2 * pi xp, yp = x + sin(ang) * rad, y + cos(ang) * rad xp, yp = int(xp), int(yp) if self.inbounds(xp, yp): score += self.explode(xp, yp) self.fall() self.give_score(round(score / 1.7), self.brickgetpos(y, x)) def laser(self, x, y): score = 0 coords = [] for i in range(self.HB): for j in range(-1, 1 + 1, 1): coords.append((x + j, i)) for i in range(self.WB): coords.append((i, y)) for i in range(-self.HB, self.HB): coords.append((x + i, y + i)) for i in range(-self.WB, self.WB): coords.append((x - i, y + i)) bc = 0 for x, y in coords: if not self.inbounds(x, y): continue score += self.explode(x, y) self.fall() self.give_score(score, self.brickgetpos(y, x)) def getty(self, x, y): if not self.inbounds(x, y) or not self.net[x][y].is_on: return -1 else: return self.net[x][y].brick_type def popupt(self, text, position_, font_=("Arial", 30), color_="white"): label = LabelNode(text, font=font_, color=color_, parent=self, position=position_) label.run_action(A.sequence(A.wait(1), A.call(label.remove_from_parent))) def give_score(self, count, xy): self.last_score = int(count ** 2.5) size = 10 if self.last_score > 50000: size = 60 elif self.last_score > 20000: size = 40 elif self.last_score > 10000: size = 30 elif self.last_score > 5000: size = 25 elif self.last_score > 2000: size = 20 elif self.last_score > 1000: size = 15 if self.last_score > 0: self.popupt("+" + str(self.last_score), xy, font_=("Chalkduster", int(size * 1.5))) self.update_scores() def touch_began(self, touch): if not self.game_on: return x, y = touch.location x, y = x + self.W / 2, y + self.H / 2 W, H = get_screen_size() x, y = x, y x, y = int(x), int(y) x, y = x - self.Woff, y - self.Hoff x, y = x // self.W, y // self.H if not self.inbounds(x, y): return count = self.react(self.net[x][y].brick_type, x, y, True) self.demark() if self.getty(x, y) in [0, 1, 2, 3]: if count >= 2: self.react(self.net[x][y].brick_type, x, y) self.fall() self.give_score(count, touch.location) elif self.getty(x, y) == 4: self.bomb(x, y, 5 * count) elif self.getty(x, y) == 5: self.explode(x, y) self.fall() self.update_cells() def explode(self, x, y): if self.net[x][y].is_on: self.net[x][y].destroy() self.gems[self.net[x][y].brick_type] += 1 s = str(self.gems[self.net[x][y].brick_type]) self.lt[self.net[x][y].brick_type].text = " " * len(s) + ": " + s self.game_node.add_child(Explosion(self.net[x][y])) return True else: return False def react(self, col, x, y, ignore=False): if self.inbounds(x, y) and self.net[x][y].brick_type == col and self.net[x][y].is_on and self.net[x][y].lf and self.net[x][y].enabled: if not ignore: self.explode(x, y) else: self.net[x][y].mark() r = 1 r += self.react(col, x + 1, y + 0, ignore) r += self.react(col, x - 1, y - 0, ignore) r += self.react(col, x + 0, y + 1, ignore) r += self.react(col, x - 0, y - 1, ignore) return r else: return 0 def destroy_brick(self, x, y): self.net[x][y].destroy() run(Game(), LANDSCAPE, show_fps=True) 


晶体工作演示:

Source: https://habr.com/ru/post/zh-CN464805/


All Articles