{"id":141,"date":"2024-06-07T09:02:34","date_gmt":"2024-06-07T12:02:34","guid":{"rendered":"http:\/\/pplay.local\/?page_id=141"},"modified":"2024-06-19T13:27:08","modified_gmt":"2024-06-19T16:27:08","slug":"criando-um-space-invaders","status":"publish","type":"page","link":"http:\/\/www2.ic.uff.br\/pplay\/tutoriais\/criando-um-space-invaders\/","title":{"rendered":"Criando um Space Invaders"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Criando o arquivo-fonte do jogo<\/h2>\n\n\n\n<p>O primeiro passo no desenvolvimento do seu jogo \u00e9 a cria\u00e7\u00e3o do arquivo-fonte. Ap\u00f3s escolher a pasta onde ir\u00e1 armazenar os arquivos do jogo, crie um arquivo chamado&nbsp;<em>SpaceInvaders.py.&nbsp;<\/em>Voc\u00ea pode criar esse arquivo utilizando um editor de texto ou IDE de sua prefer\u00eancia. Ent\u00e3o crie seu pacote de imagens e \u00e1udios a medida que for desenvolvendo seu jogo de modo que seus arquivos fiquem coerentes com o jogo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Importa\u00e7\u00f5es<\/h2>\n\n\n\n<p>Agora a programa\u00e7\u00e3o come\u00e7a de verdade! Abra o arquivo&nbsp;<em>SpaceInvaders.py&nbsp;<\/em>para edi\u00e7\u00e3o<em>.<\/em>&nbsp;Primeiramente, vamos importar as classes do&nbsp;<em>PPlay<\/em>&nbsp;que ser\u00e3o necess\u00e1rias para o nosso projeto:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from pplay.window import *\nfrom pplay.sprite import *\nfrom pplay.gameimage import *\nfrom pplay.sound import *<\/code><\/pre>\n\n\n\n<p>Para saber mais, visite a documenta\u00e7\u00e3o das classes\u00a0<a href=\"http:\/\/www2.ic.uff.br\/pplay\/documentacao\/window\" data-type=\"link\" data-id=\"http:\/\/www2.ic.uff.br\/pplay\/documentacao\/window\">Window<\/a>,\u00a0<a href=\"http:\/\/www2.ic.uff.br\/pplay\/documentacao\/sprite\" data-type=\"page\" data-id=\"119\">Sprite<\/a>, <a href=\"http:\/\/www2.ic.uff.br\/pplay\/documentacao\/gameimage\/\" data-type=\"page\" data-id=\"107\">GameImage<\/a>\u00a0e\u00a0<a href=\"http:\/\/www2.ic.uff.br\/pplay\/tutoriais\/tutorial-sound\/\" data-type=\"page\" data-id=\"391\">Sound<\/a>.<\/p>\n\n\n\n<p>Al\u00e9m das classes do&nbsp;<em>PPlay<\/em>, tamb\u00e9m precisaremos da classe random do&nbsp;<em>Python<\/em>. Vamos import\u00e1-la e gerar uma&nbsp;<em>seed<\/em>, que \u00e9 um valor inteiro usado para a gera\u00e7\u00e3o de n\u00fameros aleat\u00f3rios:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import random\nrandom.seed()<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Vari\u00e1veis globais<\/h2>\n\n\n\n<p>Nesse passo, criaremos duas vari\u00e1veis globais que auxiliar\u00e3o no controle do jogo. A primeira \u00e9 a&nbsp;<em>GAME_SPEED<\/em>, que \u00e9 utilizada para controlar a velocidade do jogo e \u00e9 muito \u00fatil para efetuar testes. A segunda \u00e9 chamada&nbsp;<em>GAME_STATE<\/em>, que controla o estado atual do jogo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>GAME_SPEED = 1\nGAME_STATE = 0\n\n\"\"\"\nControla em que est\u00e1gio o jogo se encontra:\n0 - Menu Inicial\n1 - Jogo\n2 - Finaliza\u00e7\u00e3o do jogo (Pontua\u00e7\u00e3o)\n\"\"\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Criando a janela do jogo<\/h2>\n\n\n\n<p>Agora, criaremos a janela do jogo. O primeiro passo \u00e9 definir quais ser\u00e3o as dimens\u00f5es da mesma. Em nosso exemplo, usaremos 400&nbsp;<em>pixels<\/em>&nbsp;de largura e 600&nbsp;<em>pixels<\/em>&nbsp;de altura:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Largura da janela\nwidth = 400\n\n# Altura da janela\nheight = 600\n<\/code><\/pre>\n\n\n\n<p>Em seguida, definimos a cor de fundo e o t\u00edtulo da janela do jogo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Cor de fundo\nbackground_color = &#91;0, 0, 0]\n\n# T\u00edtulo da janela\ntitle = \"Space Invaders\"<\/code><\/pre>\n\n\n\n<p>Finalmente, utilizando as defini\u00e7\u00f5es que criamos anteriormente, criamos efetivamente a janela do jogo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>window = Window(width, height)\nwindow.set_title(title)\nwindow.set_background_color(background_color)<\/code><\/pre>\n\n\n\n<p>Agora definiremos as imagens de fundo da janela. Usaremos duas&nbsp;<a href=\"http:\/\/www2.ic.uff.br\/docs\/gameimage\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>GameImage<\/strong><\/a>&nbsp;iguais, para gerarmos mais \u00e0 frente um efeito de&nbsp;<em>scrolling<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Background Image - 2 para scrolling\nbackground_01 = GameImage(\"stars_background.png\")\nbackground_02 = GameImage(\"stars_background.png\")<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"105\" height=\"146\" src=\"http:\/\/www2.ic.uff.br\/pplay\/wp-content\/uploads\/2015\/07\/esquema_background.png\" alt=\"\"><\/p>\n\n\n\n<p>Logo ap\u00f3s, criamos as defini\u00e7\u00f5es do efeito de&nbsp;<em>scrolling<\/em>. O primeiro passo \u00e9 posicionar as duas imagens de fundo. A primeira (<em>background_01<\/em>) recebe a valor 0 como posi\u00e7\u00e3o vertical inicial. A segunda (<em>background_02<\/em>) recebe como posi\u00e7\u00e3o vertical o pr\u00f3prio tamanho negativado. Isso acontece para que a mesma fique posicionada logo ap\u00f3s a primeira, para que quando termine a rolagem da primeira imagem comece a rolagem da segunda, como visto no esquema ao lado:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Respectivas posi\u00e7\u00f5es iniciais\nbackground_01.y = 0\nbackground_02.y = -background_02.height<\/code><\/pre>\n\n\n\n<p>Para finalizar, definimos a vari\u00e1vel&nbsp;<em>background_roll_speed<\/em>, que&nbsp;\u00e9 respons\u00e1vel por controlar a velocidade da movimenta\u00e7\u00e3o do fundo. O efeito de&nbsp;<em>scrolling<\/em>&nbsp;ser\u00e1<br>tratado com detalhes mais \u00e0 frente no tutorial.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Velocidade de rolagem\nbackground_roll_speed = 50<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Teclado e Mouse<\/h2>\n\n\n\n<p>Nesse momento criaremos os controladores do jogo: o teclado e o mouse.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code>keyboard = window.get_keyboard()<\/code>\n<code>mouse = window.get_mouse()<\/code><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Efeito Sonoro<\/h2>\n\n\n\n<p>Agora criaremos o efeito sonoro do disparo utilizando o arquivo&nbsp;<em>bullet_sound.ogg<\/em>, presente no pacote que foi baixado e descompactado no in\u00edcio do tutorial:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code>bullet_sound =Sound(\"bullet_sound.ogg\")<\/code><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Criando a Nave do Jogador<\/h2>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"52\" height=\"33\" src=\"http:\/\/www2.ic.uff.br\/pplay\/wp-content\/uploads\/2015\/07\/ship.png\" alt=\"\"><\/p>\n\n\n\n<p>Com a janela do jogo criada e o mouse e teclado definidos, \u00e9 a hora de criar a nave que o jogador controlar\u00e1 no jogo. Primeiramente, vamos criar o\u00a0<strong><a href=\"http:\/\/www2.ic.uff.br\/pplay\/documentacao\/sprite\" data-type=\"page\" data-id=\"119\">Sprite<\/a><\/strong>\u00a0da nave usando a imagem\u00a0<em>ship.png<\/em>, tamb\u00e9m presente no pacote do princ\u00edpio do tutorial. Em seguida vamos posicion\u00e1-la centralizada, na parte inferior da janela de jogo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Sprite da nave do jogador\nplayer = Sprite(\"ship.png\")\n\n# Posi\u00e7\u00e3o inicial\nplayer.set_position((window.width - player.width) \/ 2,\n                    (window.height - player.height))<\/code><\/pre>\n\n\n\n<p>Agora que j\u00e1 posicionamos a nave do jogador, vamos definir algumas informa\u00e7\u00f5es sobre o jogador. Em primeiro lugar, definimos a velocidade do jogador. Em seguida, definimos em que dire\u00e7\u00e3o ele est\u00e1 se movendo (no caso, para cima). Por final, criamos a vari\u00e1vel que ir\u00e1 armazenar a pontua\u00e7\u00e3o do jogador:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Velocidade do jogador\nplayer.speed = 200\n\n# Dire\u00e7\u00e3o do jogador \nplayer.direction = -1  # &#91;cima]\n\n# Pontua\u00e7\u00e3o\nplayer.score = 0\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Inimigos<\/h2>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"38\" height=\"25\" src=\"http:\/\/www2.ic.uff.br\/pplay\/wp-content\/uploads\/2015\/07\/red_enemy.png\" alt=\"\"><\/p>\n\n\n\n<p>Para come\u00e7ar, definimos o endere\u00e7o&nbsp;sprite do inimigo, utilizando a imagem&nbsp;<em>red_enemy.png<\/em>. Em seguida, definimos a velocidade do movimento como 200, o mesmo valor que definimos anteriormente para a nave do jogador, e tamb\u00e9m definimos a dire\u00e7\u00e3o do movimento, que \u00e9 contr\u00e1ria \u00e0 dire\u00e7\u00e3o do movimento do jogador.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Sprite dos inimigos\nenemy_image = \"red_enemy.png\"\n\n# Velocidade dos inimigos\nenemy_speed = 200\n\n# Dire\u00e7\u00e3o dos inimigos\nenemy_direction = 1  # &#91;baixo]\n<\/code><\/pre>\n\n\n\n<p>No&nbsp;<em>Space Invaders<\/em>, os inimigos se apresentam na forma de uma matriz. Vamos agora definir as informa\u00e7\u00f5es dessa matriz de inimigos. A primeira informa\u00e7\u00e3o que declaramos a vari\u00e1vel&nbsp;<em>MAXSIZE<\/em>, que define o tamanho m\u00e1ximo de ambas as dimens\u00f5es da matriz.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Tamanho limite da matriz\nMAXSIZE = 10\n<\/code><\/pre>\n\n\n\n<p>Em seguida, usando nosso gerador de n\u00fameros aleat\u00f3rios declarado anteriormente, definimos as dimens\u00f5es horizontais e verticais da matriz. Para o n\u00famero de linhas, \u201csorteamos\u201d um valor entre 3 e 10. J\u00e1 para o n\u00famero de colunas, o valor \u201csorteado\u201d \u00e9 entre 1 e 10:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Numero de linhas da matriz\nmatrix_x = int(random.uniform(3, MAXSIZE))\n\n# Numero de coluna da matriz\nmatrix_y = int(random.uniform(1, MAXSIZE))\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">M\u00faltiplos Objetos<\/h2>\n\n\n\n<p>Nesse momento, iremos declarar dois vetores muito importantes para o jogo. O primeiro deles \u00e9 o&nbsp;<em>bullets<\/em>, que \u00e9 o conjunto dos tiros disparados pelo jogador. O segundo \u00e9 a matriz&nbsp;<em>enemies<\/em>, de tamanho 10\u00d710, que armazenar\u00e1 os nossos inimigos:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>bullets = &#91;]\nenemies = &#91;&#91;0 for x in range(10)] for x in range(10)]\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Controladores Temporais<\/h2>\n\n\n\n<p>Os controladores temporais s\u00e3o vari\u00e1veis que controlam o atraso dos disparos dos inimigos e do jogador (<em>enemy_shoot_delay<\/em>&nbsp;e&nbsp;<em>player.shoot_delay<\/em>, respectivamente). Elas s\u00e3o definidas em fun\u00e7\u00e3o da vari\u00e1vel global&nbsp;<em>GAME_SPEED<\/em>, declarada anteriormente. Em adi\u00e7\u00e3o temos a vari\u00e1vel auxiliar&nbsp;<em>player.shoot_tick<\/em><em>,&nbsp;<\/em>que ser\u00e1 usada mais \u00e0 frente em nosso tutorial:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>enemy_shoot_delay = 1 \/ GAME_SPEED\nplayer.shoot_delay = 1 \/ GAME_SPEED * 0.5\n\nplayer.shoot_tick = player.shoot_delay\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">win()<\/h2>\n\n\n\n<p>A fun\u00e7\u00e3o&nbsp;<em>win()<\/em>&nbsp;\u00e9 muito importante em nosso jogo. \u00c9 ela que define quando o jogador efetivamente \u201cganhou\u201d a partida. Caso o jogador tenha vencido, a fun\u00e7\u00e3o inicia uma nova partida.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def win():\n    \"\"\"\n    Fun\u00e7\u00e3o para verificar se o jogador ganhou\n    Caso afirmativo, reinicia o jogo\n    \"\"\"\n    # Criamos o acesso \u00e0s vari\u00e1veis globais\n    global matrix_x\n    global matrix_y\n    global GAME_STATE\n    \n    # Criamos uma vari\u00e1vel de controle, para sabermos se o jogador ganhou o jogo\n    won = True\n    \n    # Verifica em todas as linhas se ainda existe algum inimigo vivo\n    for row in range(matrix_x):\n        if won:\n            for column in range(matrix_y):\n                if enemies&#91;row]&#91;column] != 0:\n                    # Se ele encontrar algum inimigo vivo, seta a vari\u00e1vel\n                    # won como False e quebra a cadeia de repeti\u00e7\u00f5es\n                    won = False\n                    break\n    if won:\n        # Se o jogo percorrer toda a matriz e n\u00e3o encontrar\n        # nenhum inimigo vivo, reinicia o jogo\n        GAME_STATE = 2\n<\/code><\/pre>\n\n\n\n<p>Como voc\u00ea pode perceber, primeiramente setamos a vari\u00e1vel&nbsp;<em>win<\/em>&nbsp;como&nbsp;<em>True<\/em>&nbsp;e verificamos toda a matriz em busca de algum inimigo vivo. Caso nenhum seja encontrado, a vari\u00e1vel continua com seu valor original. Caso algum inimigo ainda esteja presente, o valor da vari\u00e1vel \u00e9 invertido e a sequ\u00eancia de repeti\u00e7\u00f5es \u00e9 quebrada, j\u00e1 que n\u00e3o \u00e9 necess\u00e1rio saber se existe mais de um inimigo vivo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">restart(player, enemies, bullets)<\/h2>\n\n\n\n<p>Essa fun\u00e7\u00e3o, como o pr\u00f3prio nome sugere, reinicializa o jogo. Ela \u00e9 respons\u00e1vel por excluir todos os inimigos e disparos efetuados, al\u00e9m de levar o jogador de volta ao seu estado inicial.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def restart(player, enemies, bullets):\n    \"\"\"\n    Fun\u00e7\u00e3o para (re)iniciar o jogo.\n    :param player: jogador\n    :param enemies: matriz de inimigos\n    :param bullets: lista de instancias de balas\n    \"\"\"\n    # Gera o acesso \u00e0s vari\u00e1veis globais\n    global matrix_x\n    global matrix_y\n    \n    # Deleta todos os objetos enemies e bullets\n    del enemies\n    del bullets\n    \n    # Retorna o jogador \u00e0 posi\u00e7\u00e3o e pontua\u00e7\u00e3o inicial do jogo\n    player.score = 0\n    player.set_position((window.width - player.width) \/ 2,\n                        (window.height - player.height))\n    \n    # Reinicia os contadores de disparos\n    player.shoot_tick = player.shoot_delay\n    \n    # Cria uma nova matriz de inimigos\n    matrix_x = int(random.uniform(3, 10))\n    matrix_y = int(random.uniform(1, 10))\n    spawn_enemy(matrix_x, matrix_y, enemies)\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">adjust_bullet(actor, bullet)<\/h2>\n\n\n\n<p>Definimos agora a fun\u00e7\u00e3o&nbsp;<em>adjust_bullet<\/em>&nbsp;pois ela ser\u00e1 necess\u00e1ria na pr\u00f3xima fun\u00e7\u00e3o que iremos implementar, a&nbsp;<em>shoot()<\/em>. Essa fun\u00e7\u00e3o receber como par\u00e2metros o \u201cator\u201d (ator = jogador ou inimigo) que ir\u00e1 efetuar o disparo e o projetil que ser\u00e1 disparado e ajusta a posi\u00e7\u00e3o do proj\u00e9til para que o mesmo se alinhe com o \u201cator\u201d.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def adjust_bullet(actor, bullet):\n    \"\"\"\n    Recebe o atirador e a bala, e ajusta sua posi\u00e7\u00e3o\n    :param actor: Instancia do jogador ou inimigo\n    :param bullet: Instancia do proj\u00e9til\n    \"\"\"\n    # Calcula posi\u00e7\u00e3o X da bala, utilizando como refer\u00eancia o\n    # centro do ator e armazena em x_fire\n    x_fire = actor.x + (actor.width \/ 2) - (bullet.width \/ 2)\n    \n    # Calcula posi\u00e7\u00e3o Y do proj\u00e9til, utilizando como refer\u00eancia\n    # a dire\u00e7\u00e3o de movimento e o tamanho do jogador, salvando\n    # o resultado na vari\u00e1vel y_fire\n    if actor.direction == -1:\n        y_fire = actor.y\n    elif actor.direction == 1:\n        y_fire = actor.y + actor.height - bullet.height\n    \n    # Transfere o valor das vari\u00e1veis auxiliares x_fire e y_fire\n    # para o proj\u00e9til\n    bullet.x = x_fire\n    bullet.y = y_fire\n    \n    # Define dire\u00e7\u00e3o do proj\u00e9til\n    bullet.direction = actor.direction\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">shoot(shooter)<\/h2>\n\n\n\n<p>Essa fun\u00e7\u00e3o cria um novo proj\u00e9til (bullet) e o associa ao respons\u00e1vel pelo seu disparo. Ela tamb\u00e9m reproduz o efeito sonoro do disparo e ainda zera a vari\u00e1vel&nbsp;<em>shoot_tick<\/em>&nbsp;do respons\u00e1vel pelo mesmo (falaremos mais \u00e0 frente sobre a utiliza\u00e7\u00e3o dessa vari\u00e1vel).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def shoot(shooter):\n    \"\"\"\n    Cria um bullet, associando-o a um ator\n    :param shooter: Ator respons\u00e1vel pelo disparo (jogador ou inimigo)\n    \"\"\"\n    # Reproduz o som do disparo\n    bullet_sound.play()\n    \n    # Zera o contador de \u00faltimo disparo\n    shooter.shoot_tick = 0\n    \n    # Cria uma nova bullet, dependendo de quem for que atirou\n    if shooter.direction == -1:\n        b = Sprite(\"bullet_player.png\")\n    elif shooter.direction == 1:\n        b = Sprite(\"bullet_enemy.png\")\n    \n    # Ajusta a posi\u00e7\u00e3o inicial e a dire\u00e7\u00e3o do proj\u00e9til\n    adjust_bullet(shooter, b)\n    \n    # Adiciona o novo proj\u00e9til que criamos para ser desenhado na tela\n    bullets.append(b)\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">spawn_enemy(i, j, enemy_matrix)<\/h2>\n\n\n\n<p>Dessa vez criaremos a fun\u00e7\u00e3o respons\u00e1vel por popular a matriz de inimigos. Os dados de entrada s\u00e3o&nbsp;<em>i<\/em>&nbsp;e&nbsp;<em>j<\/em>, que representam o n\u00famero de linhas e colunas da matriz respectivamente, al\u00e9m de&nbsp;<em>enemy_matrix<\/em>, que referencia a matriz dos inimigos.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def spawn_enemy(i, j, enemy_matrix):\n    \"\"\"\n    Gera a matriz de inimigos\n    :param i: numero de linhas na matriz\n    :param j: numero de colunas na matriz\n    :param enemy_matrix: matriz de inimigos\n    \"\"\"\n    # for x e for y percorrem cada elemento da matriz\n    for x in range(i):\n        for y in range(j):\n            # Cria o Sprite do inimigo\n            enemy = Sprite(enemy_image);\n            # Define a posi\u00e7\u00e3o\n            enemy.set_position(x * enemy.width, y * enemy.height)\n            # Define a dire\u00e7\u00e3o do movimento, no caso para baixo\n            enemy.direction = 1  # 1 = para baixo\n            # Define randomicamente o intervalo entre os disparos\n            enemy.shoot_delay = random.uniform(0, 15) \/ GAME_SPEED\n            # Zera a vari\u00e1vel de controle de disparos\n            enemy.shoot_tick = 0\n            # Coloca o inimigo rec\u00e9m criado na matriz\n            enemy_matrix&#91;x]&#91;y] = enemy\n<\/code><\/pre>\n\n\n\n<p>Como voc\u00ea pode perceber, o intervalo entre os disparos \u00e9 definido randomicamente para cada um dos inimigos. Isso \u00e9 feito para que o jogo seja mais din\u00e2mico, com os disparos sendo menos repetitivos. Com essa defini\u00e7\u00e3o, o jogador n\u00e3o sabe de onde vir\u00e3o os disparos quando o jogo inicia.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">scrolling(bg_bottom, bg_top, roll_speed)<\/h2>\n\n\n\n<h2 class=\"wp-block-heading has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"121\" height=\"240\" src=\"http:\/\/www2.ic.uff.br\/pplay\/wp-content\/uploads\/2015\/07\/scrolling.gif\" alt=\"\"><\/h2>\n\n\n\n<p>Anteriormente, citamos o efeito de&nbsp;<em>scrolling<\/em>, do qual essa fun\u00e7\u00e3o \u00e9 respons\u00e1vel. Esse efeito faz com que o&nbsp;<em>background<\/em>&nbsp;do nosso jogo seja aparentemente infinito.<\/p>\n\n\n\n<p>O que essa fun\u00e7\u00e3o realmente faz \u00e9 rolar as duas imagens at\u00e9 o topo da imagem de cima tocar o in\u00edcio da tela. Neste momento, as duas imagens retornam \u00e0s sua posi\u00e7\u00f5es iniciais e a rolagem come\u00e7a novamente. Veja ao lado um representa\u00e7\u00e3o gr\u00e1fica deste processo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def scrolling(bg_bottom, bg_top, roll_speed):\n    \"\"\"\n    Recebe dois background e a velocidade que devem rolar infinitamente\n    :param bg_bottom: Sprite do fundo 1\n    :param bg_top: Sprite do fundo 2\n    :param roll_speed: Velocidade de deslocamento dos fundos\n    \"\"\"\n\n    # Movimenta ambos os Sprites verticalmente\n    bg_bottom.y += roll_speed * window.delta_time()\n    bg_top.y += roll_speed * window.delta_time()\n\n    # Se a imagem do topo j\u00e1 tiver sido completamente exibida,\n    # retorna ambas imagens \u00e0s suas posi\u00e7\u00f5es iniciais\n    if bg_top.y &gt;= 0:\n        bg_bottom.y = 0\n        bg_top.y = -bg_top.height\n\n    # Renderiza as duas imagens de fundo\n    bg_bottom.draw()\n    bg_top.draw()\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">update_counters()<\/h2>\n\n\n\n<p>Essa fun\u00e7\u00e3o tem como objetivo atualizar os contadores de disparo, usando como refer\u00eancia o valor de&nbsp;<em>window.delta_time()<\/em>. Se voc\u00ea quiser saber um pouco mais sobre essa fun\u00e7\u00e3o da classe&nbsp;<em>window<\/em>, verifique a&nbsp;<a href=\"http:\/\/www2.ic.uff.br\/docs\/window\">documenta\u00e7\u00e3o da classe<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def update_counters():\n    \"\"\"\n    Atualiza contadores do jogo\n    \"\"\"\n\n    # Atualiza o contador de controle de tiro do jogador\n    player.shoot_tick += window.delta_time()\n\n    # Atualiza o contador de controle de tiro de cada inimigo\n    # presente na matriz de inimigos\n    for row in range(matrix_x):\n        for column in range(matrix_y):\n            if enemies&#91;row]&#91;column] != 0:\n                enemies&#91;row]&#91;column].shoot_tick += window.delta_time()\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">player_shoot()<\/h2>\n\n\n\n<p>O papel dessa fun\u00e7\u00e3o \u00e9 gerir os disparos do jogador. Ela fica verificando se a tecla de disparo, no caso&nbsp;<em>[espa\u00e7o]<\/em>, foi pressionada. Caso detecte esse evento, verifica se j\u00e1 passou tempo suficiente desde o \u00faltimo disparo, para o jogador n\u00e3o disparar milhares de proj\u00e9teis seguidos. Caso j\u00e1 seja hora de efetuar um novo disparo, ela chama a fun\u00e7\u00e3o&nbsp;<em>shoot()<\/em>, definida anteriormente em nosso tutorial.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def player_shoot():\n    \"\"\"\n    A\u00e7\u00e3o de atirar\n    \"\"\"\n\n    # Verifica se o jogador apertou o bot\u00e3o de disparar\n    if keyboard.key_pressed(\"space\"):\n        # Verifica se j\u00e1 pode disparar\n        if player.shoot_tick &gt; player.shoot_delay:\n            # Chama a fun\u00e7\u00e3o shoot(), para que ela efetue do disparo\n            shoot(player)\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">player_movement()<\/h2>\n\n\n\n<p>Essa fun\u00e7\u00e3o \u00e9 respons\u00e1vel por controlar o movimento do jogador. Como a nave do jogador s\u00f3 pode se mover lateralmente, chamamos apenas a fun\u00e7\u00e3o\u00a0<em>player.move_key_x()<\/em>, fun\u00e7\u00e3o da classe\u00a0<em>Sprite<\/em>\u00a0respons\u00e1vel pelo movimento lateral do mesmo. Voc\u00ea pode verificar mais informa\u00e7\u00f5es sobre essa fun\u00e7\u00e3o e sobre a classe\u00a0<em>Sprite<\/em>\u00a0na <a href=\"http:\/\/www2.ic.uff.br\/pplay\/documentacao\/sprite\" data-type=\"page\" data-id=\"119\">documenta\u00e7\u00e3o da classe<\/a>.<\/p>\n\n\n\n<p>Al\u00e9m de movimentar a nave, essa fun\u00e7\u00e3o tamb\u00e9m controla a posi\u00e7\u00e3o m\u00e1xima e m\u00ednima da mesma para que ela n\u00e3o ultrapasse os limites laterais da janela de jogo.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def player_movement():\n    \"\"\"\n    A\u00e7\u00e3o de movimento da nave do jogador\n    \"\"\"\n\n    # Atualiza a posi\u00e7\u00e3o do jogador\n    player.move_key_x(player.speed * window.delta_time() * GAME_SPEED)\n\n    # N\u00e3o permite que a lateral esquerda da nave ultrapasse a\n    # lateral esquerda da tela, onde x = 0\n    if player.x &lt;= 0:\n        player.x = 0\n\n    # N\u00e3o permite que a lateral esquerda da nave ultrapasse a\n    # lateral direita da tela, onde x = largura da tela.\n    if player.x + player.width &gt;= window.width:\n        player.x = window.width - player.width\n<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"81\" height=\"119\" src=\"http:\/\/www2.ic.uff.br\/pplay\/wp-content\/uploads\/2015\/07\/posship.png\" alt=\"\"><\/p>\n\n\n\n<p>Como voc\u00ea pode perceber, o limite direito da tela \u00e9 definido por largura da tela menos o tamanho do&nbsp;<em>Sprite<\/em>&nbsp;da nave. Isso acontece pois a posi\u00e7\u00e3o x de um&nbsp;<em>Sprite<\/em>&nbsp;\u00e9 definido pelo canto esquerdo do mesmo. Logo, voc\u00ea precisa compensar a dist\u00e2ncia entre as laterais para manter o&nbsp;<em>Sprite<\/em>&nbsp;dentro da tela de jogo. Para um melhor entendimento dessa rela\u00e7\u00e3o, observe a imagem ao lado:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">bullet_movement()<\/h2>\n\n\n\n<p>Agora criaremos a fun\u00e7\u00e3o respons\u00e1vel por controlar os disparos efetuados no jogo, tanto os do jogador quanto os dos inimigos. Ela percorre o nosso conjunto de disparos&nbsp;<em>bullets<\/em>&nbsp;e atualiza o movimento de cada uma das inst\u00e2ncias de proj\u00e9til, na dire\u00e7\u00e3o a qual ele est\u00e1 orientado. Al\u00e9m disso, verifica se o proj\u00e9til j\u00e1 saiu dos limites da tela e o destr\u00f3i caso isso tenha ocorrido.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def bullet_movement():\n    \"\"\"\n    Realiza a movimenta\u00e7\u00e3o de cada bala em jogo\n    \"\"\"\n\n    # Para cada bala instanciada no jogo\n    for b in bullets:\n        # Atualiza a sua posi\u00e7\u00e3o, baseado em sua dire\u00e7\u00e3o\n        b.move_y(200 * b.direction * window.delta_time() * GAME_SPEED)\n        \n        # Verifica se saiu da tela e, caso tenha sa\u00eddo, destr\u00f3i o proj\u00e9til\n        if b.y &lt; -b.height or b.y &gt; window.height + b.height:\n            bullets.remove(b)\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">enemy_movement()<\/h2>\n\n\n\n<p>A fun\u00e7\u00e3o que controla o movimento dos inimigos \u00e9 um pouco mais complicada que as anteriores, pois estamos lidando com o movimento de toda a matriz de inimigos. O primeiro passo \u00e9 calcular a nova posi\u00e7\u00e3o da matriz como um todo. Ap\u00f3s definir essa posi\u00e7\u00e3o, ela entra em cada um dos inimigos e faz v\u00e1rios subprocessos.<\/p>\n\n\n\n<p>O primeiro processo que \u00e9 realizado em um inimigo \u00e9 redefinir a posi\u00e7\u00e3o atual do mesmo, utilizando a nova posi\u00e7\u00e3o da matriz como refer\u00eancia. Em seguida, ela verifica se o intervalo de disparo do inimigo j\u00e1 foi cumprido e efetua um disparo se for o caso. Logo ap\u00f3s, a fun\u00e7\u00e3o define um novo intervalo de disparo aleat\u00f3rio para o inimigo.<\/p>\n\n\n\n<p>Depois de efetuar essas opera\u00e7\u00f5es, \u00e9 hora de verificar se a matriz de inimigos j\u00e1 chegou a algum dos limites laterais da tela. Caso a matriz tenha alcan\u00e7ado alguma das laterais, invertemos o movimento da matriz, indo agora na dire\u00e7\u00e3o da parede contr\u00e1ria.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def enemy_movement():\n    \"\"\"\n    Realiza a movimenta\u00e7\u00e3o de cada inimigo\n    \"\"\"\n\n    # Acessando vari\u00e1veis globais\n    global enemy_direction\n    global enemy_speed\n\n    # Cria vari\u00e1vel de controle\n    inverted = False\n\n    # Calcula a nova posi\u00e7\u00e3o da matriz de inimigos\n    new_position = enemy_speed * enemy_direction * window.delta_time() * GAME_SPEED\n\n    # Percorre toda a matriz de inimigos\n    for row in range(matrix_x):\n        for column in range(matrix_y):\n            # Caso a posi\u00e7\u00e3o esteja preenchida, isto \u00e9, o inimigo\n            # ainda esteja vivo, efetua as a\u00e7\u00f5es em seguida\n            if enemies&#91;row]&#91;column] != 0:\n                # Move o inimigo para sua nova posi\u00e7\u00e3o\n                enemies&#91;row]&#91;column].move_x(new_position)\n\n                # Caso j\u00e1 tenha alcan\u00e7ado o intervalo de disparo,\n                # efetua um novo disparo\n                if enemies&#91;row]&#91;column].shoot_tick &gt; enemies&#91;row]&#91;column].shoot_delay:\n                    shoot(enemies&#91;row]&#91;column])\n                    enemies&#91;row]&#91;column].shoot_tick = 0\n\n                    # Gera um novo intervalo de disparo aleat\u00f3rio\n                    enemies&#91;row]&#91;column].shoot_delay = random.uniform(0, 15) \/ GAME_SPEED\n\n                # Verifica se nenhuma extremidade da matriz bateu na parede\n                if not inverted:\n                    # Se bateu na parede, ent\u00e3o inverte a dire\u00e7\u00e3o da matriz\n                    # Altera dire\u00e7\u00e3o para direita\n                    if enemies&#91;row]&#91;column].x &lt;= 0:\n                        enemy_direction = 1\n                        inverted = True\n                    # Altera dire\u00e7\u00e3o para esquerda\n                    elif enemies&#91;row]&#91;column].x + Sprite(enemy_image).width &gt;= window.width:\n                        enemy_direction = -1\n                        inverted = True\n<\/code><\/pre>\n\n\n\n<p>Verifique que, como na fun\u00e7\u00e3o&nbsp;<em>player_movement()<\/em>, que declaramos anteriormente, \u00e9 necess\u00e1rio compensar o tamanho lateral da matriz ao verificar se a mesma tocou a lateral direita da janela.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">bullet_ship_collision()<\/h2>\n\n\n\n<p>Agora que j\u00e1 temos v\u00e1rios proj\u00e9teis voando na dire\u00e7\u00e3o do jogador e dos inimigos, precisamos verificar se algum deles efetivamente acertou o alvo. Essa fun\u00e7\u00e3o percorre nosso conjunto de proj\u00e9teis&nbsp;<em>bullets<\/em>&nbsp;e verifica:<\/p>\n\n\n\n<ul>\n<li>caso o disparo seja do jogador, se atingiu algum inimigo<\/li>\n\n\n\n<li>caso o disparo seja de um inimigo, se atingiu a nave do jogador<\/li>\n<\/ul>\n\n\n\n<p>Se um disparo atingiu um inimigo, o mesmo ser\u00e1 destru\u00eddo dentro da fun\u00e7\u00e3o&nbsp;<em>check_enemy_collision()<\/em>. J\u00e1 se um disparo acertar a nave do jogador, a vari\u00e1vel global&nbsp;<em>GAME_STATE<\/em>&nbsp;recebe o valor 2, que representa o fim de jogo.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def bullet_ship_collision():\n    \"\"\"\n    Verifica se os disparos colidiram com alguma nave\n    \"\"\"\n\n    # Acessando vari\u00e1vel global\n    global GAME_STATE\n\n    # Para cada inst\u00e2ncia dos disparos\n    for b in bullets:\n        # Se for disparo do jogador\n        if b.direction == -1:\n            # Verifica se bateu em algum inimigo\n            check_enemy_collision(b)\n        \n        # Se for disparo do inimigo\n        elif b.direction == 1:\n            # Verifica se bateu no jogador\n            if b.collided(player):\n                # Se bateu no jogador, define o fim de jogo\n                GAME_STATE = 2\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">check_enemy_collision(b)<\/h2>\n\n\n\n<p>Chegamos agora na fun\u00e7\u00e3o que \u201cchamamos\u201d anteriormente. Essa fun\u00e7\u00e3o recebe uma inst\u00e2ncia de disparo e verifica em toda a lista de inimigos se houve uma colis\u00e3o. Caso tenha havido colis\u00e3o, ela destr\u00f3i a bala e o inimigo.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def check_enemy_collision(b):\n    \"\"\"\n    Verifica se o proj\u00e9til colidiu com o inimigo\n    :param b: Inst\u00e2ncia de proj\u00e9til\n    \"\"\"\n\n    # Percorre toda a matriz de inimigos\n    for row in range(matrix_x):\n        for column in range(matrix_y):\n            if enemies&#91;row]&#91;column] != 0:\n                # Se o inimigo ainda estiver vivo (enemies&#91;row]&#91;column] != 0),\n                # verifica se o disparo b colidiu com o mesmo\n                if b.collided(enemies&#91;row]&#91;column]):\n                    # Caso tenha havido colis\u00e3o, remove a bala e o\n                    # inimigo do jogo\n                    bullets.remove(b)\n                    enemies&#91;row]&#91;column] = 0\n                    # Atualiza a pontua\u00e7\u00e3o do jogador\n                    player.score += 50\n                    # Interrompe a fun\u00e7\u00e3o, pois o proj\u00e9til foi destru\u00eddo\n                    # e n\u00e3o poder\u00e1 colidir com mais nenhum inimigo\n                    return\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">bullet_bullet_collision()<\/h2>\n\n\n\n<p>Uma das caracter\u00edsticas do Space Invaders \u00e9 que voc\u00ea pode se defender dos disparos inimigos utilizando seus pr\u00f3prios disparos. Essa fun\u00e7\u00e3o \u00e9 respons\u00e1vel por verificar se quaiser dois disparos colidiram no jogo e, caso isso aconte\u00e7a, destuir ambos.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def bullet_bullet_collision():\n    \"\"\"\n    Verifica se o proj\u00e9til colidiu com alguma outro proj\u00e9til\n    \"\"\"\n\n    # Para cada inst\u00e2ncia de proj\u00e9til\n    for b1 in bullets:\n        # Se for proj\u00e9til do jogador\n        if b1.direction == -1:\n            # Verifica em todas as inst\u00e2ncias se ele colidiu com outro\n            for b2 in bullets:\n                # Verifica se o proj\u00e9til atual \u00e9 inimigo\n                if b2.direction == 1:\n                    # Se for inimigo, verifica se existiu colis\u00e3o\n                    if b1.collided(b2):\n                        # Se houver colis\u00e3o, remove os dois proj\u00e9teis\n                        bullets.remove(b1)\n                        bullets.remove(b2)\n                        break\n<\/code><\/pre>\n\n\n\n<p>Repare que ap\u00f3s destruir os disparos quando ocorre uma colis\u00e3o, existe uma linha de&nbsp;<em>break<\/em>. A fun\u00e7\u00e3o desse&nbsp;<em>break<\/em>&nbsp;\u00e9 parar de comparar o primeiro proj\u00e9til (b1) com outros proj\u00e9teis. Como ele foi destru\u00eddo, ele n\u00e3o poder\u00e1 mais colidir com nenhum outro proj\u00e9til da lista. Logo, \u201csaltamos\u201d para o pr\u00f3ximo proj\u00e9til (b1) e seguimos comparando esse novo proj\u00e9til com os outros da lista.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">draw()<\/h2>\n\n\n\n<p>Essa fun\u00e7\u00e3o \u00e9 uma das mais importantes do jogo. Ela \u00e9 respons\u00e1vel por desenhar, ou melhor dizendo,&nbsp;<em>renderizar<\/em>&nbsp;os companentes que formam o seu jogo.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def draw():\n    \"\"\"\n    Desenha todos os elementos na tela\n    \"\"\"\n\n    # Desenha todas as inst\u00e2ncias de proj\u00e9til\n    for b in bullets:\n        b.draw()\n\n    # Percorre todo a matriz de inimigos\n    for row in range(matrix_x):\n        for column in range(matrix_y):\n            # Se o inimigo estiver vivo (!=0), desenha o inimigo\n            if enemies&#91;row]&#91;column] != 0:\n                enemies&#91;row]&#91;column].draw()\n\n    # Desenha a nave do jogador\n    player.draw()\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">start_window()<\/h2>\n\n\n\n<p>Essa fun\u00e7\u00e3o, como o nome sugere, \u00e9 respons\u00e1vel por criar a janela inicial do jogo. Ela utiliza todas as vari\u00e1veis que definimos no in\u00edcio do nosso tutorial para criar a primeira partida.<\/p>\n\n\n\n<p>def start_window():<br>&#8220;&#8221;&#8221;<br>Janela inicial do jogo<br>&#8220;&#8221;&#8221;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Acessando a vari\u00e1vel global\nglobal GAME_STATE\n\n# Escreve o texto que informa as op\u00e7\u00f5es do jogador na tela\nwindow.draw_text(\"ENTER para jogar | ESC para sair\", 0, 0, 28, (255,255,255), \"Calibri\")\n\n# Se jogador pressionou 'enter', inicia o jogo\nif keyboard.key_pressed(\"enter\"):\n    # Define a vari\u00e1vel como 1, que significa que a partida est\u00e1 ativa\n    GAME_STATE = 1\n    # Reinicia o jogador, os inimigos e os disparos\n    restart(player, enemies, bullets)\n\n# Se jogador pressionou 'esc', sai do jogo\nelif keyboard.key_pressed(\"escape\"):\n    window.close()<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">restart_window()<\/h2>\n\n\n\n<p>Essa fun\u00e7\u00e3o \u00e9 chamada toda vez que uma partida chega ao final. Ela \u00e9 respons\u00e1vel por exibir a pontua\u00e7\u00e3o final do jogador e iniciar uma nova partida quando o jogador pressionar a tecla&nbsp;<em>[ENTER]<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def restart_window():\n    \"\"\"\n    Reinicia o jogo\n    \"\"\"\n\n    # Acessando vari\u00e1vel global\n    global GAME_STATE\n\n    # Escreve na tela a pontua\u00e7\u00e3o do jogador\n    window.draw_text(\"Sua pontua\u00e7\u00e3o foi:\" + str(player.score), 5, 5, 16, (255,255,255), \"Calibri\", True)\n\n    # Quando o jogador pressionar 'enter', reinicia o jogo\n    if keyboard.key_pressed(\"enter\"):\n        # Modifica o estado do jogo para 1, que significa partida ativa\n        GAME_STATE = 1\n        # Reinicia o jogador, os inimigos e os disparos\n        restart(player, enemies, bullets)\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Game Loop<\/h2>\n\n\n\n<p>Esse \u00e9 o cora\u00e7\u00e3o do nosso jogo. O&nbsp;<em>game loop<\/em>&nbsp;\u00e9 uma fun\u00e7\u00e3o que roda infinitamente (ao menos at\u00e9 ser interrompida), chamando as fun\u00e7\u00f5es do jogo que definimos durante o tutorial e coordenando toda a partida.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>while True:\n    # Apaga a tela completamente\n    window.set_background_color(background_color)\n    \n    # Chama nossa fun\u00e7\u00e3o de scrolling, que faz o fundo \n    # rolar infinitamente\n    scrolling(background_01, background_02, background_roll_speed)\n    \n    # Se o estado de jogo for = 0, quer dizer que \u00e9 a primeira\n    # vez que o game loop \u00e9 acionado. Logo, ele cria a janela do\n    # jogo.\n    if GAME_STATE == 0:\n        start_window()\n    \n    # Se n\u00e3o for a primeira vez, quer dizer que a partida ainda\n    # est\u00e1 acontecendo.\n    elif GAME_STATE == 1:\n        # Verifica se o jogador venceu a partida\n        win()\n        \n        # Atualiza os contadores\n        update_counters()\n        \n        # Atualiza a movimenta\u00e7\u00e3o do jogador\n        player_movement()\n        \n        # Controla os tiros a cada intervalo\n        player_shoot()\n        \n        # Atualiza o movimento dos disparos\n        bullet_movement()\n        \n        # Atualiza o movimento dos inimigos\n        enemy_movement()\n        \n        # Verifica a colis\u00e3o de proj\u00e9teis contra naves\n        bullet_ship_collision()\n        \n        # Verifica colis\u00f5es entre proj\u00e9teis\n        bullet_bullet_collision()\n        \n        ## Renderiza todos os dados na tela ##\n        draw()\n    \n    # Caso o jogo tenha terminado (GAME_STATE = 2), reinicia\n    # a partida do jogo.\n    elif GAME_STATE == 2:\n        restart_window()\n    \n    # Atualiza a janela de jogo cada vez que o game loop roda\n    window.update()\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Pronto! Seu Space Invaders est\u00e1 completo!<\/h2>\n\n\n\n<p>Se voc\u00ea chegou at\u00e9 esta parte do tutorial e o seu jogo funcionou corretamente, parab\u00e9ns! Voc\u00ea acabou de finalizar o seu primeiro&nbsp;<em>Space Invaders<\/em>!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">O que fazer agora?<\/h2>\n\n\n\n<p>Agora que seu jogo est\u00e1 pronto, est\u00e1 na hora de melhor\u00e1-lo! Fa\u00e7a uma lista com os melhoramentos que voc\u00ea deseja fazer em seu jogo e m\u00e3os \u00e0 obra. Caso voc\u00ea n\u00e3o tenha muitas ideias, eis algumas sugest\u00f5es de adi\u00e7\u00f5es que voc\u00ea pode fazer ao seu&nbsp;<em>Space Invaders<\/em>:<\/p>\n\n\n\n<ul>\n<li>adicionar mais efeitos sonoros (explos\u00e3o quando um inimigo \u00e9 destu\u00eddo, m\u00fasica de fundo, som do motor da nave do jogador etc);<\/li>\n\n\n\n<li>adicionar tipos diferentes de inimigos, utilizando imagens diferentes;<\/li>\n\n\n\n<li>criar um ranking de pontua\u00e7\u00f5es, para voc\u00ea poder competir com seus amigos;<\/li>\n<\/ul>\n\n\n\n<p>As possibilidades s\u00e3o infinitas! Utiliza a sua criatividade e teste os seus limites melhorando esse jogo. Agora s\u00f3 depende de voc\u00ea!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Cr\u00e9ditos do Tutorial<\/strong>:&nbsp;Ad\u00f4nis Gasiglia<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Criando o arquivo-fonte do jogo O primeiro passo no desenvolvimento do seu jogo \u00e9 a cria\u00e7\u00e3o do arquivo-fonte. Ap\u00f3s escolher a pasta onde ir\u00e1 armazenar os arquivos do jogo, crie um arquivo chamado&nbsp;SpaceInvaders.py.&nbsp;Voc\u00ea pode criar esse arquivo utilizando um editor de texto ou IDE de sua prefer\u00eancia. Ent\u00e3o crie seu pacote de imagens e \u00e1udios [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":57,"menu_order":10,"comment_status":"closed","ping_status":"closed","template":"tutorial-template.php","meta":{"footnotes":""},"_links":{"self":[{"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/pages\/141"}],"collection":[{"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/comments?post=141"}],"version-history":[{"count":20,"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/pages\/141\/revisions"}],"predecessor-version":[{"id":487,"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/pages\/141\/revisions\/487"}],"up":[{"embeddable":true,"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/pages\/57"}],"wp:attachment":[{"href":"http:\/\/www2.ic.uff.br\/pplay\/wp-json\/wp\/v2\/media?parent=141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}