... oder wie man die Zeit mit einem iPad tötet und sonst nichts ...Hallo!
Worüber sprichst du?
Leider ersetzen Tablets Computer noch nicht. Aber eine Fahrt / ein Flug ist wichtig. Deshalb habe ich nach den IDes gesucht, die sich unter dem iPad befinden, und heute werde ich das Spiel auf Pythonista machen.
Was machen wir?
Die einfachsten Programme wie Kristalle (ja, ja, genau die, die Sie in der U-Bahn spielen). Tetris, Schlange, Füllung - jeder Neuling, der ein wenig Verständnis hat, wird sie in 30 Minuten schreiben. Unter der Zwischensequenz - Screenshots, Tutorial, Code.
Hier sind ein paar Screenshots von dem, was ich vermasselt habe:
HaftungsausschlussDieser Artikel richtet sich nicht nur ausschließlich an Anfänger (die Python kennen) und ermöglicht es Ihnen nicht, in zehn Minuten eine Panzerwelt oder eine fertige Anwendung im Allgemeinen zu erstellen. Der Autor garantiert jedoch keinen absolut schönen und korrekten Code aus Sicht der Programmierreligion (obwohl er es versucht). . Und auch etwas wird aus Pythonista-Beispielen und -Dokumentationen gestohlen.
Der gesamte Code wird am Ende angegeben.Lernen Sie die Grafiken in Pythonista kennen
Importierenfrom scene import * import random
Erstellen Sie sofort eine Szene:
class Game(Scene): def setup(self): self.background_color = "green" run(Game(), LANDSCAPE)
Fangen wir gleich an. Sie sollten einen grünen Bildschirm haben. Lassen Sie uns ein paar coole Sachen machen, indem wir die Update-Methode (die das System selbst aufruft) zur Game-Klasse hinzufügen und die Hintergrundfarbe ändern.
class Game(Scene):
Jetzt wechselt unser Bildschirm reibungslos von gelb nach weiß und umgekehrt.

Erstellen Sie nun ein Objekt. Wir erstellen es auch in der Setup-Methode:
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"
Wir haben die Linie (mypath) festgelegt, einen ShapeNode darauf erstellt, die Farbe angezeigt und dann das übergeordnete Element angegeben (im Wesentlichen dasselbe - geben Sie das übergeordnete Element beim Erstellen an, d. H. ShapeNode (* ..., parent = self) oder self.add_child (obj)).
Nun, in Game.update () ändern wir die Position des Objekts (Tupel), und es ist in Pixel und wird von der unteren linken Ecke aus gezählt.
Beachten Sie, dass wir die Szene nicht neu zeichnen müssen (obwohl dies möglich ist). Objekte und Knoten, deren übergeordnetes Element die Szene ist (oder einige ihrer untergeordneten Objekte), werden selbst neu gezeichnet
Das Letzte, was wir in diesem Abschnitt durchgehen werden, ist touch_began (sowie touch_moved und touch_ended). Es ist leicht zu erraten, dass die Methode Klicks auf dem Bildschirm abfängt. Probieren wir es aus:
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

Jedes Mal, wenn Sie auf den Bildschirm klicken, erstellen wir einen Kreis. Der Ort des Klicks ist touch.location.
Bereit, eine Schlange zu schreiben
SpielmechanismusEine Schlange ist eine Anordnung von Quadraten, wenn sich der Kopf bewegt - das zweite Stück bewegt sich an die Stelle des ersten, das dritte - an die Stelle des zweiten usw. Um den Schnittpunkt des Kopfes mit dem Schwanz herauszufinden, werden wir ihn mit jedem Stück Schwanz vergleichen
Wir entfernen den gesamten geschriebenen Code, weil wir ihn mehr oder weniger schön machen wollen (aber natürlich werden wir Fahrräder machen).
Zuerst erstellen wir die PhyObj-Klasse:
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)
Ich denke, hier ist alles trivial. Innerhalb der Klasse selbst haben wir einen Knoten erstellt und einige Methoden beschrieben, mit denen unser Code besser lesbar wird.
HolivaryPersönlich ziehe ich es vor, zuerst Klassen auf niedriger Ebene zu erstellen, die viele doppelte Methoden und Eigenschaften haben, aber dann wird der Code in den Klassen auf höherer Ebene sehr schön und lesbar.
PhyObj ist das Objekt der untersten Ebene in unserem Spiel, tatsächlich ist es ein abstraktes physisches Objekt.
Beschreibung der Schlange
Jetzt müssen wir die Schlange beschreiben, und da sie aus Teilen besteht, werden wir zuerst eine beschreiben:
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"
Im Konstruktor rufen wir die übergeordnete Methode der Klasse auf und geben uns Form und Farbe. Der Rand wird benötigt, damit die Quadrate nicht zusammenkleben und eine Art Netz bilden.
class Game(Scene): def setup(self): self.tile = Tile(self, (40, 40)) self.tile.setpos(100, 100)
Es hätte sich herausstellen sollen:

Aber warum brauchen wir zum Beispiel eine 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)

Nun, aus diesen Stücken müssen Sie die Schlange kleben. Wir brauchen eine Initialisierungsmethode und eine Verschiebungsmethode.
Erstellen Sie zunächst die Initialisierung:
class Snake: def __init__(self, length, width, initpos, parent): self.width = width
Versuchen wir es gleich zu zeichnen:
class Game(Scene): def setup(self): self.snake = Snake(10, 40, (200, 200), self)

Fügen Sie die Verschiebungsmethode hinzu.
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)
Zuerst bewegen wir den letzten zum vorletzten, dann den vorletzten zum vorletzten ... dann den zweiten zum ersten. Und der erste auf (x, y).
Eigentlich bewegt sich unsere Schlange gerade gut. Versuchen wir mal:
class Game(self):
Wenn du es geschafft hast zu sehen, dann kroch sie weg, wie es sollte. Tatsache ist, dass das Update sehr oft aufgerufen wird (und übrigens optional mit demselben Intervall). Daher müssen wir berücksichtigen, wie viel Zeit seit dem letzten Aufruf vergangen ist, und warten, bis es sich genug angesammelt hat.
Kurz gesagt, wir tun:
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 gibt True zurück, wenn mehr Zeit als t vergangen ist. Jetzt bewegt sich die Schlange alle 0,3 Sekunden. Hat es geklappt?

Management
Jetzt müssen Sie die Kontrolle übernehmen, dh eine Drehung in alle vier Richtungen:

class Game(Scene):
Und jetzt müssen wir touch_began verarbeiten, um zu verstehen, in welchen Bereich der Benutzer gestochen hat. Eigentlich stellte sich heraus, dass es nicht so interessant war, wie ich dachte, also können Sie hier einfach kopieren:
class Game(Scene):
Versuchen Sie es jetzt

Der Hauptmechanismus ist ausgearbeitet, es bleibt eine Überprüfung auf Kollisionen und Äpfel.
Schwanzkollision
Beginnen wir mit der Überprüfung und fügen der Schlange die Methode find_collisions hinzu
class Snake:
Jetzt können wir ein Paar Zellen erhalten, die sich schneiden. Ich möchte sie rot färben und die Würfelmethode zu Tile hinzufügen:
class Tile(PhyObj):
Fügen Sie eine Überprüfung hinzu, um das Setup zu aktualisieren und zu ändern:
class Game(Scene):
Was ist mit mir passiert:

Es bleibt Äpfel zu machen.
Dehnung und Äpfel
Wir werden die Schlange verlängern und damit sie schön aussieht, wird ein neuer Link gemäß den letzten beiden hinzugefügt, das heißt:

Fügen Sie der Schlange die Methoden hinzu:
class Snake:
find_dir findet die Richtung, in die die Schwanzspitze unserer Heldin gerichtet ist. Anhängen, es ist leicht zu erraten, fügt eine Zelle hinzu. Füge dem Spiel eine weitere snake_lengthen-Methode hinzu:
class Game(Scene):
Die letzte Zeile wird benötigt, damit die Schlange ein wenig wartet und der Benutzer Zeit hat, um zu sehen, dass das Stück hinzugefügt wurde.
Um herauszufinden, ob sich etwas mit der Schlange schneidet, fügen Sie die Schnittmethode hinzu.
class Snake:
Hurra, es bleibt nur ein Apfel zu kreieren. Eigentlich beschreiben wir den Apfel auf einmal:
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)
Solch eine seltsame Zufälligkeit ist erforderlich, um unser Bullauge auf das Gitter zu richten. Dann ist es nicht notwendig, den Abstand zwischen der Schnauze und dem Apfel zu suchen und seinen Scheiterhaufen zu vergleichen. Nur auf ifas. Gehen wir zum Aktualisieren und fügen am Ende dieser Funktion sehr einfache Zeilen hinzu:
class Game(Scene):
Nun, alles scheint zu sein, jetzt verlängert sich die Schlange, wenn sie auf einen Apfel trifft, und stirbt, wenn sie sich selbst trifft.

Bonus
Sie können Soundeffekte erstellen:
import sound class Game(Scene):
Machen Sie eine sanfte Bewegung:
class Game(Scene):
Mit anderen Worten, wir haben die Logik der Position PhyObj geändert. Früher haben wir uns auf die Position des grafischen Elements konzentriert, und jetzt gibt es ein separates Feld für die logische Position (dh das für die Spielelogik verwendete), und die Position des grafischen Elements ist jetzt frei und kann auf seine eigene Weise geändert werden. Mit Action hinterlassen wir ihr nämlich einen parallelen Strom, in dem sie sich bewegt.
Eine so glatte Schlange stellte sich heraus:

Und zum Schluss das Etikett mit der Länge der Schlange:
class Game(Scene):

Freunde, danke für eure Aufmerksamkeit! Wenn etwas nicht klar ist, fragen Sie. Und wenn es interessant sein wird - ich werde weitermachen, gibt es noch etwas zu erzählen (aber dieser Artikel ist schon ziemlich lang).
Alle Schlangencode 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)
Crystal Code WhiteBlackGoose EditionEs ist lustig, dass ich, nachdem ich es gemacht habe, in den Beispielen von Pythonista selbst etwas SEHR Ähnliches gefunden habe. Aber ich habe ein bisschen mehr Funktionen :)
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
Demonstration der Arbeit von Kristallen: