... o cómo matar el tiempo con un ipad y nada más ...Hola
De que estas hablando
Desafortunadamente, las tabletas aún no reemplazan a las computadoras. Pero tener un viaje / vuelo es vital. Por lo tanto, busqué qué ides están debajo del ipad, y en realidad hoy haré el juego en Pythonista.
Que haremos
Los programas más simples, como los cristales (sí, sí, los mismos que juegas en el metro). Tetris, serpiente, relleno: cualquier recién llegado que tenga un poco de comprensión los escribirá en 30 minutos. Debajo de la escena: capturas de pantalla, tutorial, código.
Aquí hay algunas capturas de pantalla de lo que he estropeado:
Muchas capturas de pantalla Descargo de responsabilidadEste artículo no solo es exclusivo para principiantes (sino que conoce Python) y no le permitirá crear World of Tanks en diez minutos o cualquier aplicación preparada en general, sino que el autor no garantiza un código absolutamente hermoso y correcto desde el punto de vista de la programación de religión (aunque lo intenta) . Y también algo es robado de ejemplos y documentación de pythonista.
Todo el código se dará al final.Conozca los gráficos en pythonista
Importarfrom scene import * import random
Inmediatamente crea una escena:
class Game(Scene): def setup(self): self.background_color = "green" run(Game(), LANDSCAPE)
Bueno, comencemos de inmediato. Deberías tener una pantalla verde. Hagamos algunas cosas interesantes agregando el método de actualización (que el propio sistema llama) a la clase Game y cambiando el color de fondo.
class Game(Scene):
Ahora nuestra pantalla cambia suavemente de amarillo a blanco y viceversa.

Ahora crea algún objeto. También lo creamos en el método de configuración:
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"
Establecimos la línea (mypath), creamos un ShapeNode en él, lo apuntamos a un color y luego especificamos un padre (esencialmente lo mismo: especifique un padre al crear, es decir, ShapeNode (* ..., parent = self) o self.add_child (obj)).
Bueno, en Game.update () cambiamos la posición del objeto (tupla), y está en píxeles y se considera desde la esquina inferior izquierda.
Tenga en cuenta que no necesitamos volver a dibujar la escena (aunque es posible). Los objetos y nodos cuyo padre es la escena (o algunos de sus objetos hijos) se vuelven a dibujar
Lo último que veremos en esta sección es touch_began (así como touch_moved y touch_ended). Es fácil de adivinar, el método captura clics en la pantalla. Probémoslo:
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

Cada vez que hace clic en la pantalla, creamos un círculo, el lugar del clic es touch.location.
Listo para escribir una serpiente
Mecanismo de juegoUna serpiente es un conjunto de cuadrados, cuando la cabeza se mueve - la segunda pieza se mueve al lugar de la primera, la tercera - al lugar de la segunda, etc. Para averiguar la intersección de la cabeza con la cola, la compararemos con cada pieza de cola
Eliminamos todo el código escrito, porque queremos hacerlo más o menos bellamente (pero, por supuesto, haremos bicicletas).
Primero, creemos la clase 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)
Creo que todo es trivial aquí. Dentro de la clase en sí, creamos un nodo y también describimos algunos métodos que harán que nuestro código sea más legible.
HolivarioPersonalmente, prefiero crear primero clases de bajo nivel que tengan muchos métodos y propiedades duplicados, pero luego el código en los de nivel superior se vuelve muy hermoso y legible.
PhyObj es el objeto de nivel más bajo en nuestro juego, de hecho es un objeto físico abstracto.
Descripción de la serpiente
Ahora tenemos que describir la serpiente, y dado que consta de piezas, primero describiremos una:
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"
En el constructor, llamamos al método padre de la clase y nos damos forma y color. se necesita un margen para que los cuadrados no se peguen y creen algún tipo de malla.
class Game(Scene): def setup(self): self.tile = Tile(self, (40, 40)) self.tile.setpos(100, 100)
Debería haber resultado:

Pero, por ejemplo, ¿por qué necesitamos margen?
class Game(Scene): def setup(self): tile1 = Tile(self, (40, 40)) tile1.setpos(100, 100) tile2 = Tile(self, (40, 40)) tile2.setpos(140, 100)

Bueno, ahora de estas piezas necesitas pegar la serpiente. Necesitamos un método de inicialización y un método de movimiento.
Primero, cree la inicialización:
class Snake: def __init__(self, length, width, initpos, parent): self.width = width
Intentemos dibujarlo de inmediato:
class Game(Scene): def setup(self): self.snake = Snake(10, 40, (200, 200), self)

Bueno, agregue el método de movimiento.
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)
Primero movemos el último al penúltimo, luego el penúltimo al penúltimo ... luego el segundo al primero. Y el primero en (x, y).
En realidad, nuestra serpiente se mueve bien recta. Probemos
class Game(self):
Si lograste ver, entonces ella se arrastró como debería. El hecho es que la actualización se llama con mucha frecuencia (y, por cierto, opcionalmente con el mismo intervalo), por lo que debemos considerar cuánto tiempo ha pasado desde la última llamada y esperar hasta que se "acumule" lo suficiente.
En resumen, hacemos:
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 devuelve True si ha pasado más tiempo que t. Ahora la serpiente se moverá cada 0.3 segundos. ¿Funcionó?

Gestión
Ahora necesita hacer el control, es decir, un giro en las cuatro direcciones:

class Game(Scene):
Y ahora tenemos que hacer un procesamiento touch_began para comprender en qué área se asomó el usuario. En realidad, resultó no ser tan interesante como pensaba, así que aquí puedes simplemente copiar:
class Game(Scene):
Bueno, intenta girar ahora

El mecanismo principal está resuelto, queda por hacer una verificación de colisiones y manzanas.
Colisión de cola
Comencemos por verificar y agregar el método find_collisions a la serpiente
class Snake:
Ahora podemos obtener un par de celdas que se cruzan. Me gustaría colorearlos de rojo, agregar el método de troquel a Tile:
class Tile(PhyObj):
Agregue una marca de verificación para actualizar y cambiar la configuración:
class Game(Scene):
Lo que me paso

Queda por hacer manzanas.
Alargamiento y manzanas
Vamos a alargar la serpiente, y para que se vea hermosa, se agregará un nuevo enlace de acuerdo con los dos últimos, es decir:

Agregue los métodos a la serpiente:
class Snake:
find_dir encuentra la dirección en la que se dirige la punta de la cola de nuestra heroína. agregar, es fácil de adivinar, agrega una celda. Agregue otro método snake_lengthen al juego:
class Game(Scene):
Se necesita la última línea para que la serpiente espere un poco, y el usuario logró ver que se agregó la pieza.
Para saber si algo se cruza con la serpiente, agregue el método de intersección.
class Snake:
Hurra, solo queda crear una manzana. En realidad, describimos la manzana de una vez:
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)
Se necesita una aleatoriedad tan extraña para encajar en nuestra cuadrícula. Entonces no será necesario buscar la distancia entre el hocico y la manzana y comparar su pira-pyr. Solo en ifas. Vamos a actualizar y agregar líneas muy simples al final de esta función:
class Game(Scene):
Bueno, todo parece ser, ahora la serpiente se alarga si golpea una manzana y muere si se golpea a sí misma.

Bono
Puedes hacer efectos de sonido:
import sound class Game(Scene):
Haz un movimiento suave:
class Game(Scene):
En otras palabras, cambiamos la lógica de la posición PhyObj. Anteriormente, nos centramos en la posición del elemento gráfico, y ahora hay un campo separado para la posición lógica (es decir, el que se usa para la lógica del juego), y la posición del elemento gráfico ahora es libre y se puede cambiar de alguna manera a su manera. Es decir, usando Acción, le dejamos una corriente paralela, donde se mueve.
Una serpiente tan suave resultó:

Y finalmente, una etiqueta con una longitud de serpiente:
class Game(Scene):

Amigos, gracias por su atención! Si algo no está claro, pregunte. Y si será interesante, continuaré, todavía hay algo que contar (pero este artículo ya es bastante largo).
Todo el código de la serpiente 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)
Código de cristal WhiteBlackGoose editionEs curioso que después de haberlo hecho, encontré algo MUY similar en los ejemplos del propio pythonista. Pero tengo un poco más de características :)
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
Demostración del trabajo de los cristales: