Como criar um jogo 2D com Python e a biblioteca Arcade

Compartilhe!

Como criar um jogo 2D com Python e a biblioteca Arcade

Python é uma linguagem excelente para pessoas que estão aprendendo a programar e perfeita para quem deseja “fazer as coisas” e não perder muito tempo em código clichê. Arcade é uma biblioteca Python para a criação de videogames 2D que é fácil de usar e muito capaz à medida que você ganha experiência. Neste artigo, explicarei como começar a usar Python e Arcade para programar videogames.

Comecei o desenvolvimento no Arcade depois de ensinar os alunos usando a biblioteca PyGame . Eu ensinei pessoalmente usando o PyGame por quase 10 anos e desenvolvi o ProgramArcadeGames.com para ensinar online. PyGame é ótimo, mas eventualmente eu senti que estava perdendo tempo tendo que cobrir bugs que nunca foram corrigidos .

Eu me preocupava em ensinar coisas como o loop de eventos , que não era mais a forma como codificamos. Tive uma seção inteira na qual expliquei por que as coordenadas y estavam invertidas. Como o PyGame raramente era atualizado e se baseava em uma biblioteca SDL 1 antiga , em vez de algo mais moderno como OpenGL , eu não tinha muita esperança no futuro.Mais recursos Python

Eu queria uma biblioteca que fosse mais fácil de usar, mais poderosa e usasse alguns dos novos recursos do Python 3, como decoradores e dicas de tipo. Arcade é isso. E é assim que começar.

Instalação

O Arcade, como muitos outros pacotes, está disponível via PyPi , o que significa que você pode instalar o Arcade usando o pipcomando (ou o comando pipenv ). Se você já tem o Python instalado, provavelmente pode apenas abrir um prompt de comando no Windows e digitar:

pip install arcade

Ou em MacOS e Linux digite:

pip3 install arcade

Para obter instruções de instalação mais detalhadas, você pode consultar a documentação de instalação do Arcade .

Desenho simples

Você pode abrir uma janela e criar desenhos simples com apenas algumas linhas de código. Vamos criar um exemplo que desenhe um rosto sorridente como a figura abaixo:

imagem de rosto de sorriso

O script abaixo mostra como você pode usar os comandos de desenho do Arcade para fazer isso. Observe que você não precisa saber como usar classes ou mesmo definir funções . Programar com feedback visual rápido é ótimo para quem deseja começar a aprender a programar.

import arcade

# Set constants for the screen size
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600

# Open the window. Set the window title and dimensions (width and height)
arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing Example")

# Set the background color to white.
# For a list of named colors see:
# http://arcade.academy/arcade.color.html
# Colors can also be specified in (red, green, blue) format and
# (red, green, blue, alpha) format.
arcade.set_background_color(arcade.color.WHITE)

# Start the render process. This must be done before any drawing commands.
arcade.start_render()

# Draw the face
x = 300
y = 300
radius = 200
arcade.draw_circle_filled(x, y, radius, arcade.color.YELLOW)

# Draw the right eye
x = 370
y = 350
radius = 20
arcade.draw_circle_filled(x, y, radius, arcade.color.BLACK)

# Draw the left eye
x = 230
y = 350
radius = 20
arcade.draw_circle_filled(x, y, radius, arcade.color.BLACK)

# Draw the smile
x = 300
y = 280
width = 120
height = 100
start_angle = 190
end_angle = 350
arcade.draw_arc_outline(x, y, width, height, arcade.color.BLACK, start_angle, end_angle, 10)

# Finish drawing and display the result
arcade.finish_render()

# Keep the window open until the user hits the 'close' button
arcade.run()

Usando funções

Obviamente, escrever código no contexto global não é uma boa forma. Felizmente, é fácil melhorar seu programa usando funções. Aqui podemos ver um exemplo de desenho de um pinheiro em um local específico (x, y) usando uma função:

def draw_pine_tree(x, y):
    """ This function draws a pine tree at the specified location. """
   
    # Draw the triangle on top of the trunk.
    # We need three x, y points for the triangle.
    arcade.draw_triangle_filled(x + 40, y,       # Point 1
                                x, y - 100,      # Point 2
                                x + 80, y - 100, # Point 3
                                arcade.color.DARK_GREEN)

    # Draw the trunk
    arcade.draw_lrtb_rectangle_filled(x + 30, x + 50, y - 100, y - 140,
                                      arcade.color.DARK_BROWN)

Para o exemplo completo, veja o desenho com funções .

classes e funções

O programador mais experiente saberá que os programas gráficos modernos carregam primeiro as informações do desenho na placa gráfica e, em seguida, solicitam à placa gráfica que as desenhe posteriormente em lote. O Arcade também suporta isso . Desenhar 10.000 retângulos individualmente leva cerca de 0,800 segundos. Desenhá-los em lote leva menos de 0,001 segundos.

A classe Window

Programas maiores normalmente derivam da classe Window ou usam decoradores . Isso permite que um programador escreva código para lidar com desenho, atualização e manipulação de entrada do usuário. Um modelo para um Window baseado em início está abaixo.

import arcade

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600


class MyGame(arcade.Window):
    """ Main application class. """

    def __init__(self, width, height):
        super().__init__(width, height)

        arcade.set_background_color(arcade.color.AMAZON)

    def setup(self):
        # Set up your game here
        pass

    def on_draw(self):
        """ Render the screen. """
        arcade.start_render()
        # Your drawing code goes here

    def update(self, delta_time):
        """ All the logic to move, and the game logic goes here. """
        pass


def main():
    game = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT)
    game.setup()
    arcade.run()


if __name__ == "__main__":
    main()

Windowclasse possui vários métodos que seus programas podem substituir para fornecer funcionalidade ao programa. Aqui estão alguns dos mais comumente usados:

  • on_draw: Todo o código para desenhar a tela vai aqui.
  • update: Todo o código para mover seus itens e executar a lógica do jogo vai aqui. Isso é chamado cerca de 60 vezes por segundo.
  • on_key_press: Lida com eventos quando uma tecla é pressionada, como dar velocidade a um jogador.
  • on_key_release: Lidar com quando uma tecla é liberada, aqui você pode impedir um jogador de se mover.
  • on_mouse_motion: Isso é chamado sempre que o mouse se move.
  • on_mouse_press: Chamado quando um botão do mouse é pressionado.
  • set_viewport: Esta função é usada em jogos de rolagem, quando você tem um mundo muito maior do que pode ser visto em uma tela. A chamada set_viewportpermite que um programador defina que parte desse mundo está visível no momento.

Sprites

Sprites são uma maneira fácil de criar um objeto de bitmap 2D no Arcade. O Arcade tem métodos que tornam mais fácil desenhar, mover e animar sprites. Você também pode usar sprites facilmente para detectar colisões entre objetos.

Criando um sprite

Criar uma instância da classe Sprite do Arcade a partir de um gráfico é fácil. Um programador só precisa do nome do arquivo de uma imagem para basear o sprite e, opcionalmente, de um número para aumentar ou diminuir a imagem. Por exemplo:

SPRITE_SCALING_COIN = 0.2

coin = arcade.Sprite("coin_01.png", SPRITE_SCALING_COIN)

Este código irá criar um sprite usando a imagem armazenada em coin_01.png. A imagem será reduzida a 20% de sua altura e largura originais.

sprites coletando moedas

Listas de Sprites

Sprites normalmente são organizados em listas. Essas listas tornam mais fácil gerenciar os sprites. Sprites em uma lista usarão OpenGL para desenhar em lote os sprites como um grupo. O código abaixo configura um jogo com um jogador e um monte de moedas para o jogador coletar. Usamos duas listas, uma para o jogador e outra para as moedas.

def setup(self):
    """ Set up the game and initialize the variables. """

    # Create the sprite lists
    self.player_list = arcade.SpriteList()
    self.coin_list = arcade.SpriteList()

    # Score
    self.score = 0

    # Set up the player
    # Character image from kenney.nl
    self.player_sprite = arcade.Sprite("images/character.png", SPRITE_SCALING_PLAYER)
    self.player_sprite.center_x = 50 # Starting position
    self.player_sprite.center_y = 50
    self.player_list.append(self.player_sprite)

    # Create the coins
    for i in range(COIN_COUNT):

        # Create the coin instance
        # Coin image from kenney.nl
        coin = arcade.Sprite("images/coin_01.png", SPRITE_SCALING_COIN)

        # Position the coin
        coin.center_x = random.randrange(SCREEN_WIDTH)
        coin.center_y = random.randrange(SCREEN_HEIGHT)

        # Add the coin to the lists
        self.coin_list.append(coin)

Podemos desenhar facilmente todas as moedas nas listas de moedas:

def on_draw(self):
    """ Draw everything """
    arcade.start_render()
    self.coin_list.draw()
    self.player_list.draw()

Detectando colisões de sprites

A função check_for_collision_with_listnos permite ver se um sprite se choca com outro sprite em uma lista. Podemos usar isso para ver todas as moedas com as quais o jogador sprite está em contato. Usando um forloop simples , podemos nos livrar da moeda do jogo e aumentar nossa pontuação.

def update(self, delta_time):
    # Generate a list of all coin sprites that collided with the player.
    coins_hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.coin_list)

    # Loop through each colliding sprite, remove it, and add to the score.
    for coin in coins_hit_list:
        coin.kill()
        self.score += 1

Para obter o exemplo completo, consulte collect_coins.py .

Física do jogo

Muitos jogos incluem algum tipo de física. Os mais simples são os programas de cima para baixo que impedem o jogador de atravessar paredes. Platformers adicionam mais complexidade com gravidade e plataformas que se movem. Alguns jogos usam um mecanismo de física 2D completo com massa, fricção, molas e muito mais.

Jogos de cima para baixo

Primavera movendo-se para as paredes

Para jogos simples baseados em cima para baixo, um programa Arcade precisa de uma lista de paredes pelas quais o jogador (ou qualquer outra coisa) não pode passar. Normalmente chamo isso wall_list. Em seguida, um mecanismo de física é criado no Windowcódigo de configuração da classe com:

self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)

player_spriterecebe um vetor de movimento com seus dois atributos change_xchange_y. Um exemplo simples de fazer isso seria fazer o jogador se mover com o teclado. Por exemplo, isso pode ser no filho personalizado da Windowclasse:

MOVEMENT_SPEED = 5

def on_key_press(self, key, modifiers):
    """Called whenever a key is pressed. """

    if key == arcade.key.UP:
        self.player_sprite.change_y = MOVEMENT_SPEED
    elif key == arcade.key.DOWN:
        self.player_sprite.change_y = -MOVEMENT_SPEED
    elif key == arcade.key.LEFT:
        self.player_sprite.change_x = -MOVEMENT_SPEED
    elif key == arcade.key.RIGHT:
        self.player_sprite.change_x = MOVEMENT_SPEED

def on_key_release(self, key, modifiers):
    """Called when the user releases a key. """

    if key == arcade.key.UP or key == arcade.key.DOWN:
        self.player_sprite.change_y = 0
    elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
        self.player_sprite.change_x = 0

Embora esse código defina a velocidade do jogador, ele não move o jogador. No updatemétodo da Windowclasse, a chamada physics_engine.update()moverá o jogador, mas não através das paredes.

def update(self, delta_time):
    """ Movement and game logic """

     self.physics_engine.update()

Para um exemplo completo, consulte sprite_move_walls.py .

Platformers

mapa com mosaico de sprite

Mover-se para um jogo de plataforma com vista lateral é bastante fácil. Um programador só precisa ligar o mecanismo de física PhysicsEnginePlatformere adicionar a constante de gravidade.

self.physics_engine = arcade.PhysicsEnginePlatformer(self.player_sprite,
                                                     self.wall_list,
                                                     gravity_constant=GRAVITY)

Você pode usar um programa como o Tiled para colocar as telhas / blocos que compõem o seu nível.

Para obter um exemplo, consulte sprite_tiled_map.py .

Para física 2D completa, você pode integrar a biblioteca PyMunk .

Aprenda pelo exemplo

Uma das melhores maneiras de aprender é pelo exemplo. A biblioteca do Arcade tem uma longa lista de programas de exemplo que uma pessoa pode usar para criar jogos. Cada um desses exemplos mostra um conceito de jogo que os alunos solicitaram em minhas aulas ou online ao longo dos anos.

Executar qualquer uma dessas demos é fácil depois que o Arcade for instalado. Cada uma das amostras tem um comentário no início do programa com um comando que você pode digitar na linha de comando para executar a amostra, por exemplo:

python -m arcade.examples.sprite_moving_platforms

Resumo

O Arcade permite que você comece a programar gráficos e jogos com um código fácil de entender. Muitos novos programadores criaram ótimos jogos pouco depois de começar. De uma chance!

Créditos: https://opensource.com/article/18/4/easy-2d-game-creation-python-and-arcade

Compartilhe!