... ou comment tuer le temps avec un iPad et rien de plus ...Salut
De quoi tu parles?
Malheureusement, les tablettes ne remplacent pas encore les ordinateurs. Mais avoir un tour / vol est vital. Par conséquent, j'ai cherché ce que sont les ides sous l'ipad, et en fait aujourd'hui je ferai le jeu sur Pythonista.
Que ferons-nous?
Les programmes les plus simples, comme les cristaux (oui, oui, ceux-là mêmes que vous jouez dans le métro). Tetris, snake, fill - tout nouveau venu, ayant un peu de compréhension, les écrira en 30 minutes. Sous la cinématique - captures d'écran, tutoriel, code.
Voici quelques captures d'écran de ce que j'ai foiré:
De nombreuses captures d'écran Clause de non-responsabilitéCet article n'est pas uniquement destiné aux débutants (mais connaissant le python) et ne vous permettra pas de créer un monde de tanks en dix minutes ou toute application prête à l'emploi en général, mais l'auteur ne garantit pas un code absolument beau et correct du point de vue de la programmation de la religion (bien qu'il essaie) . Et aussi quelque chose est volé à partir d'exemples et de documentation pythonistes.
Tout le code sera donné à la fin.Apprenez à connaître les graphiques en pythonista
Importerfrom scene import * import random
Créez immédiatement une scène:
class Game(Scene): def setup(self): self.background_color = "green" run(Game(), LANDSCAPE)
Eh bien, commençons tout de suite. Vous devriez avoir un écran vert. Faisons quelques trucs sympas en ajoutant la méthode de mise à jour (que le système lui-même appelle) à la classe Game et en changeant la couleur d'arrière-plan.
class Game(Scene):
Maintenant, notre écran passe du jaune au blanc et vice versa.

Créez maintenant un objet. Nous le créons également dans la méthode de configuration:
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"
Nous définissons la ligne (mypath), créons un ShapeNode dessus, le pointons sur une couleur, puis spécifions un parent (essentiellement la même chose - spécifiez un parent lors de la création, c'est-à-dire ShapeNode (* ..., parent = self) ou self.add_child (obj)).
Eh bien, dans Game.update (), nous changeons la position de l'objet (tuple), et il est en pixels et est compté à partir du coin inférieur gauche.
Notez que nous n'avons pas besoin de redessiner la scène (bien que cela soit possible). Les objets et les nœuds dont le parent est la scène (ou certains de ses objets enfants) sont eux-mêmes redessinés
La dernière chose que nous allons parcourir dans cette section est touch_began (ainsi que touch_moved et touch_ended). C'est facile à deviner, la méthode capture les clics sur l'écran. Essayons-le:
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

Chaque fois que vous cliquez sur l'écran, nous créons un cercle, l'emplacement du clic est touch.location.
Prêt à écrire un serpent
Mécanisme de jeuUn serpent est un tableau de carrés, lorsque la tête se déplace - la deuxième pièce se déplace à la place de la première, la troisième - à la place du second, etc. Pour découvrir l'intersection de la tête avec la queue, nous la comparerons avec chaque morceau de queue
Nous supprimons tout le code écrit, car nous voulons le faire plus ou moins joliment (mais, bien sûr, nous ferons des vélos).
Commençons par créer la classe 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)
Je pense que tout est trivial ici. À l'intérieur de la classe elle-même, nous avons créé un nœud et décrit également quelques méthodes qui rendront notre code plus lisible.
HolivaryPersonnellement, je préfère d'abord créer des classes de bas niveau qui ont beaucoup de méthodes et de propriétés en double, mais ensuite le code dans les classes de niveau supérieur devient très beau et lisible.
PhyObj est l'objet de niveau le plus bas de notre jeu, en fait c'est un objet physique abstrait.
Description du serpent
Maintenant, nous devons décrire le serpent, et puisqu'il se compose de morceaux, nous allons d'abord en décrire un:
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"
Dans le constructeur, nous appelons la méthode parent de la classe et nous nous donnons forme et couleur. une marge est nécessaire pour que les carrés ne collent pas ensemble et créent une sorte de maille.
class Game(Scene): def setup(self): self.tile = Tile(self, (40, 40)) self.tile.setpos(100, 100)
Il aurait dû s'avérer:

Mais par exemple, pourquoi avons-nous besoin de marge:
class Game(Scene): def setup(self): tile1 = Tile(self, (40, 40)) tile1.setpos(100, 100) tile2 = Tile(self, (40, 40)) tile2.setpos(140, 100)

Eh bien, maintenant, à partir de ces pièces, vous devez coller le serpent. Nous avons besoin d'une méthode d'initialisation et d'une méthode de déplacement.
Créez d'abord l'initialisation:
class Snake: def __init__(self, length, width, initpos, parent): self.width = width
Essayons de le dessiner tout de suite:
class Game(Scene): def setup(self): self.snake = Snake(10, 40, (200, 200), self)

Eh bien, ajoutez la méthode de déplacement.
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)
D'abord, nous passons le dernier à l'avant-dernier, puis l'avant-dernier à l'avant-dernier ... puis le second au premier. Et le premier sur (x, y).
En fait, notre serpent se déplace bien droit. Essayons:
class Game(self):
Si vous avez réussi à voir, alors elle a rampé comme il se doit. Le fait est que la mise à jour est appelée très souvent (et soit dit en passant, éventuellement avec le même intervalle), nous devons donc considérer combien de temps s'est écoulé depuis le dernier appel et attendre qu'elle «s'accumule» suffisamment.
En bref, nous faisons:
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)
time_gone renvoie True si plus de temps s'est écoulé que t. Maintenant, le serpent se déplacera toutes les 0,3 secondes. Cela at-il fonctionné?

La gestion
Maintenant, vous devez prendre le contrôle, c'est-à-dire un virage dans les quatre directions:

class Game(Scene):
Et maintenant, nous devons effectuer un traitement touch_began pour comprendre dans quelle zone l'utilisateur a pénétré. En fait, il s'est avéré que ce n'était pas aussi intéressant que je le pensais, alors ici vous pouvez simplement copier:
class Game(Scene):
Eh bien, essayez de vous tourner maintenant

Le mécanisme principal est élaboré, il reste à faire un contrôle des collisions et des pommes.
Collision de queue
Commençons par vérifier et ajouter la méthode find_collisions au serpent
class Snake:
Maintenant, nous pouvons obtenir une paire de cellules qui se croisent. Je voudrais les colorer en rouge, ajouter la méthode de découpe à Tile:
class Tile(PhyObj):
Ajoutez un chèque pour mettre à jour et modifier la configuration:
class Game(Scene):
Qu'est-ce qui m'est arrivé:

Reste à faire des pommes.
Allongement et pommes
Nous allons allonger le serpent, et pour le rendre beau, un nouveau lien sera ajouté conformément aux deux derniers, à savoir:

Ajoutez les méthodes au serpent:
class Snake:
find_dir trouve la direction dans laquelle la pointe de la queue de notre héroïne est dirigée. ajouter, il est facile de deviner, ajoute une cellule. Ajoutez une autre méthode snake_lengthen au jeu:
class Game(Scene):
La dernière ligne est nécessaire pour que le serpent attend un peu et que l'utilisateur ait le temps de voir que la pièce a été ajoutée.
Pour savoir si quelque chose croise le serpent, ajoutez-y la méthode d'intersection.
class Snake:
Hourra, il ne reste plus qu'à créer une pomme. En fait, nous décrivons la pomme en une seule fois:
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)
Un tel hasard étrange est nécessaire pour s'adapter à notre œil de taureau sur la grille. Ensuite, il ne sera pas nécessaire de rechercher la distance entre le museau et la pomme et de comparer son pyre-pyr. Juste sur ifas. Allons mettre à jour et ajouter des lignes très simples à la fin de cette fonction:
class Game(Scene):
Eh bien, tout semble aller, maintenant le serpent s'allonge s'il frappe une pomme et meurt s'il se frappe.

Bonus
Vous pouvez créer des effets sonores:
import sound class Game(Scene):
Faites un mouvement fluide:
class Game(Scene):
En d'autres termes, nous avons changé la logique de la position PhyObj. Auparavant, nous nous sommes concentrés sur la position de l'élément graphique, et maintenant il y a un champ séparé pour la position logique (c'est-à-dire celui utilisé pour la logique du jeu), et la position de l'élément graphique est maintenant libre et peut être modifiée d'une manière ou d'une autre à sa manière. À savoir, en utilisant Action, nous lui laissons un flux parallèle, où elle se déplace.
Un serpent si lisse s'est avéré:

Et enfin, l'étiquette avec la longueur du serpent:
class Game(Scene):

Amis, merci de votre attention! Si quelque chose n'est pas clair, demandez. Et si ça va être intéressant - je vais continuer, il y a encore quelque chose à dire (mais cet article est déjà assez long).
Tout le code de serpent 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)
Code cristal Édition WhiteBlackGooseC'est drôle qu'après l'avoir fait, j'ai trouvé quelque chose de TRÈS similaire dans les exemples de la pythonista elle-même. Mais j'ai un peu plus de fonctionnalités :)
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
Démonstration du travail des cristaux: