Belajar Cara Membuat Game 2D dengan Python dan Arcade

Takagi Fujimaru 25 April 2018

Belajar Cara Membuat Game 2D dengan Python dan Arcade

Python adalah bahasa pemrograman yang sangat bagus bagi orang yang ingin belajar membuat program, serta sempurna untuk siapapun yang ingin menyelesaikan suatu permasalahan tanpa bergantung pada boilerplate code. Arcade adalah library Python untuk membuat game 2D yang mudah digunakan dan bisa dipakai untuk berbagai hal saat kita sudah berpengalaman menggunakannya. Di artikel ini, kita akan belajar bagaimana menggunakan Python dan Arcade untuk membuat game.

Penulis asli tutorial ini telah menggunakan PyGame (library lain untuk membuat game) selama hampir 10 tahun. Alasan Ia berganti menggunakan Arcade ialah karena banyaknya bug PyGame yang belum pernah diperbaiki.

Pemasangan

Arcade, seperti package Python lainnya tersedia lewat PyPi yang artinya bisa kita pasang dengan perintah pip (atau perintah pipenv). Jika suda memasang Python sebelumnya, buka sebuah jendela command prompt baru di Windows dan ketikkan:

pip install arcadepip install arcade

Atau di MacOS dan Linux tuliskan:

pip3 install arcade

Untuk lebih lengkapnya, lihat halaman Arcade installation documentation.

Membuat Gambar Sederhana

Kita bisa membuat gambar sederhana seperti gambar senyum di bawah ini dengan beberapa baris kode:

smile face image

Kodekode di bawah menunjukkan bagaimana kita bisa menggunakan perintah Arcade untuk menggambarnya. Perhatikan bahwa kita tidak perlu menulis kelas bahkan fungsi. Pemrograman yang bisa memberikan umpan balik visual sangat bermanfaat untuk orang yang baru belajar pemrograman.

import arcade # Mengatur ukuran layar SCREEN_WIDTH = 600 SCREEN_HEIGHT = 600 # Membuka jendela baru. Mengatur nama jendela dan dimensinya (lebar dan tinggi) arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing Example") # Mengatur warna latar belakang menjadi putih # Untuk daftar nama warna lihat: # http://arcade.academy/arcade.color.html # Warna bisa juga dipakai dalam format (red, green, blue) dan # (red, green, blue, alpha). arcade.set_background_color(arcade.color.WHITE) # Mulai proses render. Harus ditulis sebelum perintah drawing. arcade.start_render() # Menggambar wajah x = 300 y = 300 radius = 200 arcade.draw_circle_filled(x, y, radius, arcade.color.YELLOW) # Menggambar mata kanan x = 370 y = 350 radius = 20 arcade.draw_circle_filled(x, y, radius, arcade.color.BLACK) # Menggambar mata kiri x = 230 y = 350 radius = 20 arcade.draw_circle_filled(x, y, radius, arcade.color.BLACK) # Menggambar senyum 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) # Menampilkan hasil gambar (drawing) arcade.finish_render() # Biarkan jendela terbuka sampai user menutupnya dengan tombol 'close arcade.run()

Menggunakan Fungsi

Tentu saja, menulis kode di global context kurang baik untuk dilakukan. Untungnya, menulis program dengan fungsi tidak sulit dilakukan. Di bawah ini adalah contoh dimana kita menggambar pohon pinus di posisi (x, y) tertentu dengan sebuah fungsi:

def draw_pine_tree(x, y): """ This function draws a pine tree at the specified location. """ # Menggambar segitiga di bagian atas. # Kita butuh tiga poin x, y untuk menggambar segitiga arcade.draw_triangle_filled(x + 40, y, # Poin 1 x, y - 100, # Poin 2 x + 80, y - 100, # Poin 3 arcade.color.DARK_GREEN) # Menggambar batang pohonnya arcade.draw_lrtb_rectangle_filled(x + 30, x + 50, y - 100, y - 140, arcade.color.DARK_BROWN)

Untuk contoh lengkapnya, lihat drawing with functions.

classes and functions

Programmer yang lebih berpengalaman akan tahu bahwa program harus memuat gambar terlebih dahulu ke kartu grafis sebelum meminta kartu grafis tersebut untuk menampilkannya sebagai sebuah batch. Arcade mendukung teknik ini. Menggambar 10.000 persegi panjang satu persatu akan memakan waktu 0.800 detik. Menggambar mereka sebagai batch hanya memerlukan waktu 0.001 detik.

Kelas Window

Program yang lebih besar biasanya akan diturunkan dari kelas Window, atau menggunakan decorator. Hal ini memungkinkan programmer untuk menulis kode yang melakukan proses gambar, mengubah, dan meng-handle input dari user di fungsi yang telah ditentukan. Template untuk program berbasis Window adalah sebagai berikut:

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()

Kelas Window memiliki beberapa method yang bisa di-override (ditimpa dengan menambah proses khusus oleh kita sendiri) untuk mengubah fungsi sebuah program. Berikut beberapa fungsi yang paling umum:

  • on_draw: Seluruh kode untuk menggambar layar ditulis di sini.
  • update: Semua kode untuk memindahkan konten game ditulis disini. Fungsi ini akan dipanggil sekitar 60 kali tiap detik.
  • on_key_press: Mendeteksi setiap kali sebuah tombol ditekan.
  • on_key_release: Mendeteksi saat sebuah tombol dilepas setelah ditekan.
  • on_mouse_motion: Dipanggil setiap kali mouse bergerak.
  • on_mouse_press: Dipanggil saat tombol mouse di tekan.
  • set_viewport: Fungsi ini dipakai di game scrolling, saat dunia game lebih luas dari apa yang dilihat di layar. Memanggil set_viewport memungkinkan programmer untuk mengatur bagian dunia game mana yang akan tampil ke layar.

Sprites

Sprites adalah sebuah teknik membuat objek 2D di Arcade. Arcade memiliki sebuah metode untuk mempermudah menampilkan, menggerakkan, dan menganimasikan sprites. Kita juga bisa memakai sprites untuk mendeteksi tabrakan antar objek.

Membuat sebuah sprite

Membuat sebuah instance kelas Sprite Arcade sangat mudah. Programmer hanya memerlukan nama file dari gambar yang ingin ditampilkan, lalu sebuah angka untuk mengskalakan (memperbesar atau memperkecil berdasarkan rasio). Misal:

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

Kode ini akan membuat sebuah sprite menggunakan gambar yang disimpan di file coin_01.png. Gambar ini akan diperkecil menjadi 20% dari ukuran aslinya.

sprites collecting coins

Spites Lists

Sprites biasanya dikelompokkan kedalam list. List ini dibuat untuk mempermudah manajemen sprites tersebut. Sprites di dalam lists menggunakan OpenGL untuk melakukan batch-draw sprites sebagai group. Kode di bawah menyiapkan sebuah game dengan satu karakter pemain, dan beberapa koin yang bisa diambil oleh pemain. Kita memiliki dua list, satu untuk karakter pemain dan satu lagi untuk koin.

def setup(self): """ Set up the game and initialize the variables. """ # Membuat list sprite self.player_list = arcade.SpriteList() self.coin_list = arcade.SpriteList() # Skor self.score = 0 # Menyiapkan pemain # Gambar karakter dari kenney.nl self.player_sprite = arcade.Sprite("images/character.png", SPRITE_SCALING_PLAYER) self.player_sprite.center_x = 50 # Posisi awal pemain self.player_sprite.center_y = 50 self.player_list.append(self.player_sprite) # Membuat koin for i in range(COIN_COUNT): # Membuat instance koin # Gambar koin dari kenney.nl coin = arcade.Sprite("images/coin_01.png", SPRITE_SCALING_COIN) # Posisi koin coin.center_x = random.randrange(SCREEN_WIDTH) coin.center_y = random.randrange(SCREEN_HEIGHT) # Menambah koin ke lists self.coin_list.append(coin)

Kita lalu bisa menggambar semua koin di dalam lists:

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

Mendeteksi tabrakan sprite

Fungsi check_for_collision_with_lists memungkinkan kita untuk mendeteksi apakah ada sebuah sprite yang bertabrakan dengan sprite lain di dalam sebuah list. Kita bisa memanfaatkannya untuk mengetahui koin dan disentuh oleh pemain. Dengan menggunakan forloop, kita bisa menghapus koin dari game (untuk koin yang disentuh) dan menaikkan skor.

def update(self, delta_time): # Membuat list koin yang bertabrakan dengan pemain coins_hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.coin_list) # Lakukan looping ke sprite yang ditabrak, lalu, hapus dari game, dan tambahkan skor for coin in coins_hit_list: coin.kill() self.score += 1

Untuk contoh lebih lengkap, cek http://arcade.academy/examples/sprite_collect_coins.html

Physics

Banyak game memiliki fitur physics untuk mensimulasikan gravitasi atau "efek nyata" lainnya. Misal, kita mungkin tidak ingin pemain untuk melewati sebuah dinding.

Game top-down

spring moving to walls

Untuk game *top-down *sederhana, program Arcade memerlukan sebuah list dinding yang tidak bisa ditembus oleh pemain (atau objek lainnya). Penulis biasanya memberinya nama wall_list. Lalu sebuah engine physics dibuat di kelas Window dengan kode:

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

Objek player_sprite diberikan sebuah movement vector dengan dua atribut yaitu change_x dan change_y. Contoh sederhananya ialah kita ingin menggerakkan karakter pemain dengan tombol panah di keyboard:

MOVEMENT_SPEED = 5 def on_key_press(self, key, modifiers): """Dipanggil setiap tombol di tekan. """ 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): """Dipanggil setiap tombol dilepas. """ 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

Meskipun kode di atas mengatur kecepatan pemain, ia tidak menggerakkannya. Pada method update di kelas Window, memanggil physics_engine.update() akan menggerakkan pemain, tapi tidak menembus dinding.

def update(self, delta_time): """ Menggerakkan pemain """ self.physics_engine.update()

Untuk kode lengkapnya lihat http://arcade.academy/examples/sprite_move_walls.html

Platformers

sprite tiled map

Bergerak ke samping untuk game platformer cukup mudah. Programmer hanya perlu mengganti engine physics-nya ke PhysicsEnginePlatformer dan menambahkan konstanta gravity:

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

Pembaca bisa memakai program seperti Tiled untuk menyusun* tiles/block *yang menjadi sebuah level.

Untuk contoh lengkap, lihat file http://arcade.academy/examples/sprite_tiled_map.html

Untuk engine physics 2D yang lebih lengkap, lihat libarary PyMunk.

Belajar dari contoh

Salah satu cara belajar paling baik ialah melalui contoh. Library Arcade memiliki banyak contoh program yang bisa dilihat untuk mengetahui proses pembuatannya. Contoh-contoh ini menunjukkan konsep yang banyak ditanyakan oleh orang yang belajar membuat game.

Jika Arcade sudah terpasang, menjalankan contoh program di atas sangat mudah. Setiap contoh memiliki komentar di bagian awal program dengan perintah yang harus dijalankan untuk memuat contoh tersebut, misalnya:

python -m arcade.examples.sprite_moving_platforms

Penutup

Arcade memungkinkan kita untuk membuat game dengan kode yang mudah dipahami. Banyak programmer baru telah membuat game menarik tidak lama setelah mereka mulai belajar. Selamat mencoba.

Diterjemahkan dari How to create a 2D game with Python and the Arcade library karya Paul Vincent Craven