Game lengkap yang saya buat di konsol windows biasa

Halo!



Hari ini saya akan menjelaskan secara rinci bagaimana saya membuat game di baris perintah, dan seberapa bagus hasilnya.



Dari mana ide itu berasal?



Sekilas saya terinspirasi oleh gagasan melakukan sesuatu yang sederhana, tetapi pada saat yang sama menarik dalam hal pengembangan. Saya mendapat ide untuk membuat game di konsol, menarik dari segi pengembangan, dan akan menarik untuk dilihat bahkan dari luar, seperti game ini .



Mesin game



Jadi, mari kita mulai dengan bagaimana game ini disusun di root, dan apa ide kerjanya.



Pertama, saya memutuskan bagaimana dunia game akan ditampilkan di konsol. Saya menyadari bahwa untuk menampilkan objek game, kami memerlukan daftar yang menyimpan daftar lain yang menyimpan karakter, yang kemudian ditampilkan di lapangan bermain dalam satu lingkaran for.



Dengan kode ini:



for line_words in OUTPUT_IMAGE:
       for word in line_words:
           print(word, end="")
       print("\n", end="")


Di sini kami menggambar semua karakter dari daftar, dan pergi ke baris baru untuk menggambar daftar karakter berikutnya.



Ini adalah bagaimana variabel yang menyimpan daftar simbol terlihat seperti:



gambar



Di sini kita segera mendapatkan keputusan tentang cara menampilkan objek dengan X dan Y, sekarang kita dapat menentukan:



X - simbol dalam daftar

Y - daftar yang berisi X

Jadi, gambarlah simbol di lapangan ... Kami akan menggunakan ini saat menggambar objek game.



Kita bisa mencoba menggambar "bola" di lapangan, menggantikan huruf "O" untuk X dan Y.



Untuk melakukan ini, tulis kode berikut:



import os
OUTPUT_IMAGE = [
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        ]

OUTPUT_IMAGE[4][6] = "O"
os.system("cls||clear")
for line_words in OUTPUT_IMAGE:
       for word in line_words:
           print(word, end="")
       print("\n", end="")



gambar



Jadi, kami telah menggambar sebuah objek di lapangan permainan kami. Benar, koordinat X dan Y bukanlah klasik. Pertama, kami menunjukkan Y pertama, kemudian X, yang tidak sesuai dengan klasik, dan kedua, koordinat Y harus meningkat untuk menaikkan objek, dalam kasus kami, sebaliknya, itu harus berkurang.



Grafik X dan Y di dalam game:



gambar



Fitur ini nantinya juga harus diperhitungkan ketika kita melakukan tabrakan pada objek di konsol.



Sekarang kita dapat mencoba untuk memindahkan objek kita melintasi lapangan permainan, mis. menciptakan gerakan.



Kita perlu membersihkan konsol untuk menghapus gambar lama dari lapangan permainan tersebut.

Kami akan melakukan ini dengan perintah:



os.system("cls||clear")


Juga, kita perlu mengganti variabel OUTPUT_IMAGEuntuk menghapus semua objek yang sebelumnya digambar di lapangan.



Kami juga harus memasukkan semua ini while True.



Mari tambahkan while Truefungsi time.sleep(1)untuk membatasi FPS.



Jadi, kode itu ditarik di depan mata kita:



from time import sleep
from os import system
OUTPUT_IMAGE = [
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
        ]

x = 0
y = 0
while True:
      sleep(1)
      system("cls||clear")
      OUTPUT_IMAGE[y][x] = "O"
      for line_words in OUTPUT_IMAGE:
             for word in line_words:
                 print(word, end="")
             print("\n", end="")
      y += 1
      x += 1
      OUTPUT_IMAGE = [
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            ]


gambar



Sekarang kami memiliki kemampuan untuk mendistribusikan objek ke seluruh bidang.



Benar, objek-objek ini terlalu primitif, dan kita harus belajar cara menggambar objek kompleks seperti pemain, rumah, makanan ...



Untuk menggambar objek yang kompleks, kita perlu memahami dan mencari cara menggambar objek dengan menentukan hanya sekali X dan Y.



Untuk ini kita perlu fungsi yang menerima gambar (simbol), X, Y;



Mari kita lakukan:



def SetImage(image: str, x: int, y: int):
    pass


Sekarang kita perlu menerapkannya. Untuk melakukan ini, Anda perlu memutuskan cara menggambar gambar yang membentang di sepanjang sumbu X dan Y, saya menemukan ini:

menggambar objek dengan membaginya menjadi simbol, dan segera setelah karakter "\ n" ditemukan, tambahkan sumbu



Y. Sumbu Y, seperti yang kami katakan, salah, terbalik, jadi kami menambahkannya untuk menurunkan objek.



Contoh gambar yang digambar menurut prinsip saya:



image = " O\n'|'\n |"#


Sekarang mari kita gambarkan ini dalam fungsi kita:



def SetImage(x: int, y: int, image: str):
  x_start = x
  x = x
  y = y
  for word in image:
      if word == "\n":
          x = x_start
          y += 1
      else:
          x += 1
          try:
            OUTPUT_IMAGE[y][x] = word
          except IndexError:
              break


Mari tambahkan try: except()untuk menghindari kesalahan jika objek memiliki X dan Y terlalu kecil atau terlalu besar.



x_startIni adalah X, dari mana kita perlu mulai menggambar saat menambah Y (dengan karakter "\ n")



Sekarang kita bisa menggunakan fungsi kita, jatuhkan X dan Y ke dalamnya, dan gambar yang perlu digambar:



Kode
from time import sleep
from os import system
OUTPUT_IMAGE = [
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      ]

def SetImage(x: int, y: int, image: str):
  x_start = x
  x = x
  y = y
  for word in image:
      if word == "\n":
          x = x_start
          y += 1
      else:
          x += 1
          try:
            OUTPUT_IMAGE[y][x] = word
          except IndexError:
              break
while True:
      sleep(1)
      system("cls||clear")
      SetImage(x=3,y=4,image=" O\n'|'\n |")
      for line_words in OUTPUT_IMAGE:
             for word in line_words:
                 print(word, end="")
             print("\n", end="")
      OUTPUT_IMAGE = [
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            ]




Dan inilah yang kami dapatkan:



gambar



seperti bola yang kami tarik, bola dapat dipindahkan di sepanjang sumbu X dan Y.



Kode
from time import sleep
from os import system
OUTPUT_IMAGE = [
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      ]
px = 0
py = 0
def SetImage(x: int, y: int, image: str):
  x_start = x
  x = x
  y = y
  for word in image:
      if word == "\n":
          x = x_start
          y += 1
      else:
          x += 1
          try:
            OUTPUT_IMAGE[y][x] = word
          except IndexError:
              break
while True:
      sleep(1)
      system("cls||clear")
      SetImage(x=px,y=py,image=" O\n'|'\n |")
      for line_words in OUTPUT_IMAGE:
             for word in line_words:
                 print(word, end="")
             print("\n", end="")
      px += 1
      py += 1
      OUTPUT_IMAGE = [
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            ]




gambar



Dan sekarang, pemain sudah bergerak di sekitar peta.



Di sini kami sudah melakukan banyak hal, sudah ada pemain, sudah ada peta, dan sepertinya sudah memungkinkan untuk membuat game, tetapi tidak. Kita membutuhkan fungsi untuk menghitung tabrakan objek, karena jenis permainan apa itu tanpa interaksi objek? Jadi mari kita mulai.



Pertama, kita perlu membuat fungsi untuk mendapatkan latitude dan height suatu objek untuk menghitung hitboxnya.



Jadi, saya memutuskan untuk membuat fungsi sesuai dengan logika berikut:



X - hitbox objek dalam lebar X, ini adalah jumlah karakter terbesar di antara karakter "\ n" di gambar

Y - hitbox di Y adalah jumlah karakter "\ n" di gambar



Dengan logika ini, tidak sulit buat fungsi yang mengambil gambar, menghitung semua karakter antara "\ n" untuk itu, dan memilih jumlah karakter terbesar dari ini - garis lintang diperoleh.

Dan jika Anda menghitung karakter "\ n", seperti yang sudah saya tulis, Anda mendapatkan tingginya.



Fungsinya ternyata seperti ini:



def GetSizeObject(img: str):
    w = 0
    weights = []
    h = [word for word in img if word == "\n"]

    for word in img:
      if word == "\n":
          weights.append(w)
          w = 0
      else:
          w += 1
      try:
          return {"w": max(weights), "h":len(h)}
      except ValueError:
            return {"w": 0, "h":0}



Mengapa ValueError kecuali di sini?
.



Jadi mari menggambar pemain kita, dan menghitung lebar dan panjangnya.



kode dengan menggambar dan menghitung lintang dan tinggi
from time import sleep
from os import system
OUTPUT_IMAGE = [
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      ]
px = 3
py = 3
def SetImage(x: int, y: int, image: str):
    global OUTPUT_IMAGE      
    x_start = x
    x = x
    y = y
    for word in image:
        if word == "\n":
            x = x_start
            y += 1
        else:
            x += 1
            try:
              OUTPUT_IMAGE[y][x] = word
            except IndexError:
                break

def GetSizeObject(img: str):
    w = 0
    weights = []
    h = [word for word in img if word == "\n"]
    h.append(1)

    for word in img:
        if word == "\n":
            weights.append(w)
            w = 0
        else:
            w += 1
    try:
        return {"w": max(weights), "h":len(h)}
    except ValueError:
        return {"w": 0, "h":0}

player_image = " O\n'|'\n |"
def draw():
      global OUTPUT_IMAGE
      sleep(1)
      system("cls||clear")
      for line_words in OUTPUT_IMAGE:
             for word in line_words:
                 print(word, end="")
             print("\n", end="")
      OUTPUT_IMAGE = [
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            ]
while True:
    SetImage(x=px,y=py,image=player_image)
    print(GetSizeObject(img=player_image))
    draw()





Hore! kita memiliki fungsi untuk menghitung latitude dan height, sekarang kita harus membuat fungsi untuk menghitung hitbox dan tabrakan objek.



Ingatlah bahwa sistem koordinat kita bukanlah sistem klasik, jadi, sayangnya, kita tidak dapat menggunakan fungsi klasik, kita harus membuatnya sendiri. Untuk melakukan ini, saya menggambar 2 kotak pada grafik yang bertabrakan, dan dari gambar ini Anda bisa mendapatkan kondisi untuk menghitung tabrakan.



Untuk memudahkan pemahaman, saya menggambar kotak hit, yaitu kotak:



gambar



Logika dalam kata-kata




x — X

y — Y

h —

w —

x2 — X

y2 — Y

h2 —

w2 —



:





y y2 - h2 + h y - h y2 + h2 - h



y2 y - h + h2 y2 - h2 y + h - h2

2 ?
2 , - / .



Y



X, Y, y — x, h — w.



:



x x2 - w2 + w x - w x2 + w2 - w







x2 x - w + w2 x2 - w2 x + w - w2



X



Logika dalam kode
, :



def IsClash(x: int, y: int, h: int, w: int,x2: int, y2: int, h2: int, w2: int):
    if (y >= y2 - h2 + h and y - h <= y2 + h2 - h) or (y2 >= y - h + h2 and y2 - h2 <= y + h - h2):
        if (x >= x2 - w2 + w and x - w <= x2 + w2 - w) or (x2 >= x - w + w2 and x2 - w2 <= x + w - w2):
            return True

    return False


True , False .



Saya juga menggambar kubus di lapangan bermain kami sehingga pemain memiliki seseorang untuk dihadapi.



Dan saya mencoba cara kerja fungsi kalkulasi tabrakan.



Berikut adalah pemain menyentuh kubus:



gambar



Tapi tidak menyentuh:



gambar



Kode kontak
/ :



from time import sleep
from os import system
OUTPUT_IMAGE = [
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
      ]

def SetImage(x: int, y: int, image: str):
    global OUTPUT_IMAGE      
    x_start = x
    x = x
    y = y
    for word in image:
        if word == "\n":
            x = x_start
            y += 1
        else:
            x += 1
            try:
              OUTPUT_IMAGE[y][x] = word
            except IndexError:
                break

def GetSizeObject(img: str):
    w = 0
    weights = []
    h = [word for word in img if word == "\n"]
    h.append(1)

    for word in img:
        if word == "\n":
            weights.append(w)
            w = 0
        else:
            w += 1
    try:
        return {"w": max(weights), "h":len(h)}
    except ValueError:
        return {"w": 0, "h":0}

def IsClash(x: int, y: int, h: int, w: int,x2: int, y2: int, h2: int, w2: int):
    if (y >= y2 - h2 + h and y - h <= y2 + h2 - h) or (y2 >= y - h + h2 and y2 - h2 <= y + h - h2):
        if (x >= x2 - w2 + w and x - w <= x2 + w2 - w) or (x2 >= x - w + w2 and x2 - w2 <= x + w - w2):
            return True

    return False

player_image = " O\n'|'\n |"
cube_image = "____\n|  |\n----"
cx = 5#
cy = 4  #          
px = 10  #
py = 3#
def draw():
      global OUTPUT_IMAGE
      sleep(1)
      system("cls||clear")
      for line_words in OUTPUT_IMAGE:
             for word in line_words:
                 print(word, end="")
             print("\n", end="")
      OUTPUT_IMAGE = [
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            [".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
            ]
while True:
    SetImage(x=px,y=py,image=player_image)
    SetImage(x=cx,y=cy,image=cube_image)
    print("is clash: ",IsClash(
      x=px,
      x2=cx,
      y=py,
      y2=cy,
      h=GetSizeObject(img=player_image)["h"],
      h2=GetSizeObject(img=cube_image)["h"],
      w=GetSizeObject(img=player_image)["w"],
      w2=GetSizeObject(img=cube_image)["w"],
      ))
    draw()





Sekarang kami memiliki semua fungsi awal untuk gim, sebenarnya, saya menulis gim saya berdasarkan mereka.



Permainan



Ide dari permainan ini adalah:



Ada seorang pemain, makanan muncul di sekitarnya, yang dipaksa untuk dikumpulkan agar tidak mati. Gim ini juga memiliki fungsi: mengambil makanan, memasukkannya ke dalam inventaris Anda, memakannya dari inventaris Anda, meletakkan item dari inventaris Anda di lantai.



Saya mulai dengan membuat loop game dalam 3 baris, sederhana While True:



from time import sleep
while True:
    sleep(0.1)


Kemudian saya menganggap perlu untuk membuat kelas di mana semua fungsi objek masa depan akan disimpan. Oleh karena itu, saya membuat file main.py dan folder lib, tempat saya meletakkan file lib.py di mana kelas game itu berada. MEREKA. file game terlihat seperti ini:



+----game
|    + -- 
|    | -- main.py
|    \ --lib
|         +--lib.py -> class Game()
|         \
|
+---


Di masa depan, saya bekerja terutama dengan kelas Game (), di main.py saya hanya menyebutnya, membuat objek awal, dan meluncurkan game.



Di kelas game, saya membuat fungsi run () yang memulai loop game. Saya juga membuat fungsi draw_all (), itu menghapus semua objek masa lalu, menggambar yang baru, dan mencetak ke lapangan bermain.



Dan seperti inilah tampilan kelasnya:



from time import sleep


class Game():
    def __init__(self):
        self.OUTPUT_IMAGE = []  #   

    def draw_all(self):
        for line_words in self.OUTPUT_IMAGE:
            for word in line_words:
                print(word, end="")
            print("\n", end="")

    def run(self):
        while True:
            self.draw_all()
            sleep(0.1)



Saya menambahkan semua fungsi dasar dari jenis set_image(), size_object(), is_clash(), dan semua orang yang mesin permainan, dan yang saya telah dijelaskan di atas.



Membuat fungsi baru create_object()dan variabel self.OBJECTS, fungsi create_object()saya gunakan untuk membuat objek, dibutuhkan parameter img, name, x, y, up, rigid, data.



img- gambar objek -

namenama objek (rumah, rumput, penghuni, makanan, dll.)

x- objek X - objek

yY

up- jika parameter ini benar, maka objek akan ditarik ke atas pemain, jika tidak pemain tumpang tindih

rigid- kekerasan, pemain tidak bisa melalui objek ini (belum diimplementasikan)

data- data pribadi objek, karakteristik pribadinya



create_object ()
:



def CreateObject(self,x: int, y: int, img: str, name: str = None, up: bool = False, rigid: bool = False, data: dict = {}):
    size_object = self.GetSizeObject(img=img)
    self.OBJECTS.append(
        {"name": name,
         "x": x,
         "y": y,
         "up": up,
         "rigid": rigid,
         "h":size_object["h"],
         "w":size_object["w"],
         "id":uuid4().hex,
         "data":data,
         "img": img}
    )




Saat itu, saya sudah menambahkan pemain, rumah, rumput, dan penduduk desa.



Dan saya memutuskan untuk menggunakan parameter yang sama di objek up, menggunakannya di objek Home, mis. sehingga rumah menutupi pemain. Untuk melakukan ini, saya membuat fungsi CheckAll (), loop for melewati semua objek, dan menggambarnya pada gambar keluar, mis. gunakan fungsi SetImage (x: int, y: int, img: str), memasok X dan Y objek, dan sebuah gambar.



Karena itu, dia menggambar objek yang bisa ditutup sendiri oleh pemain. Dalam siklus yang sama, saya mendeklarasikan list up_of_payer_objects, dan jika objek telah up = True, maka saya menambahkannya ke daftar tanpa menggambarnya di lapangan. Setelah itu saya menggambar pemain itu sendiri, dan baru kemudian saya melalui loop for atas objek di up_of_payer_objects, menggambarnya, sehingga mereka berada di atas pemain.



def CheckAll(self):
    up_of_payer_objects = []
    for object_now in range(len(self.OBJECTS)):
        if object_now["up"]:
            up_of_payer_objects.append(object_now)
            continue
        self.SetImage(x=object_now["x"],y=object_now["y"],image=object_now["img"])


Kemudian saya mulai memindahkan pemain. Untuk ini, saya membuatnya sebagai objek terpisah, yang tidak ada dalam daftar self.OBJECTS, tetapi disimpan dalam variabel self.PLAYER.



Semua parameter sesuai dengan jenis X, Y, img, ITP Anda bisa mendapatkannya dengan menggunakan tombol, dengan kata lain ini adalah kamus (dikt). Dengan pemain dan objek seperti itu, sudah mungkin untuk bekerja, bergerak, menghitung tabrakan. Saya mulai dengan bergerak.

Saya mulai membuat gerakan dengan melakukan fungsi CheckKeysObjects (), yang bertanggung jawab untuk melacak penekanan tombol, dan yang saya panggil dalam fungsi CheckAll () di awal



def CheckAll(self):
    self.CheckKeysObjects()
    ....


Untuk melacak penekanan tombol, saya menggunakan perpustakaan keyboard , dan 4 variabel: Dan semuanya ternyata sederhana, kami melacak tombolnya, dan jika ditekan , kami membuat variabel . Di awal fungsi, kami mendeklarasikan semua variabel di , untuk menyetel ulang semua hasil sebelumnya, jika tidak, pemain tidak akan berhenti.



self.WALK_LEFT_PLAYER

self.WALK_RIGHT_PLAYER

self.WALK_UP_PLAYER

self.WALK_DOWN_PLAYER



dself.WALK_RIGHT_PLAYERTrue



False



CheckKeysObjects ()
def CheckKeysObjects(self):
    #    False,    
    self.WALK_LEFT_PLAYER = False
    self.WALK_RIGHT_PLAYER = False
    self.WALK_UP_PLAYER = False
    self.WALK_DOWN_PLAYER = False
    #    
    if keyboard.is_pressed("a"):
        self.WALK_LEFT_PLAYER = True
    elif keyboard.is_pressed("d"):
        self.WALK_RIGHT_PLAYER = True
    if keyboard.is_pressed("w"):
        self.WALK_UP_PLAYER = True
    elif keyboard.is_pressed("s"):
        self.WALK_DOWN_PLAYER = True




Setelah itu, di fungsinya, saya CheckAll()memeriksa semua variabel yang bertanggung jawab atas gerakan, mencari tahu kemana pemain itu bergerak.



Jika ada yang masuk True, cari tahu yang mana, dan pindahkan benda ke arah yang berlawanan.



Kode gerakan yang dihasilkan
def CheckAll(self):
    self.CheckKeysObjects()  # check moves
    up_of_payer_objects = []
    for object_now in range(len(self.OBJECTS)):
        self.PLAYER["img"] = self.PLAYER["image_normal"]
        if self.WALK_LEFT_PLAYER:
            self.OBJECTS[object_now]["x"] += 1

        elif self.WALK_RIGHT_PLAYER:
            self.OBJECTS[object_now]["x"] -= 1


        if self.WALK_UP_PLAYER:

            self.OBJECTS[object_now]["y"] += 1
        elif self.WALK_DOWN_PLAYER:

            self.OBJECTS[object_now]["y"] -= 1




Ya, kami memindahkan objek ke arah yang berlawanan untuk menciptakan ilusi gerakan. Jika pemain pergi ke kanan, maka semua item lingkungan bergeser ke kiri.



Kemudian saya menambahkan lebih banyak item lingkungan, dan mulai memijah makanan, tujuan pemain adalah mengumpulkan makanan agar tidak mati.



Untuk menghitung mundur waktu pemijahan makanan, saya menggunakan yang sederhana time.sleep()dan perpustakaan threading- untuk menjalankan 2 fungsi pada saat yang sama, pemijahan makanan dan putaran permainan utama. Fungsi pemijahan makanan SpawnEat()hanyalah fungsi yang, ketika diluncurkan, menghasilkan makanan di tempat acak, memanggil fungsi untuk setiap unit makanan CreateObject().



Juga, setelah saya membuat fungsi pemijahan makanan, saya membuat variabel untuk pemainself.PLAYER["hungry"], ini adalah rasa laparnya, pada awalnya sama dengan 100 unit, saya akan menguranginya jika pemain berjalan dan menghabiskan energi (seperti energi, tidak ada dalam permainan) atau meningkatkannya jika pemain makan sesuatu.



Saya juga membuat sebuah fungsi MinimizeHungry(), itu dipanggil setiap 5 detik, dan hanya membutuhkan 2 unit kelaparan dari pemain. Saya melakukan ini agar pemain harus bergerak, dan tidak diam.



Terakhir, dalam sebuah fungsi Eat(), fungsi ini dipanggil di thread terpisah dari game loop. Dia memeriksa apakah ada terlalu banyak makanan di peta jika ada lebih dari 10 unit makanan. itu TIDAK memanggil fungsi SpawnEat()jika kurang dari 10 unit. lalu menelepon SpawnEat().



Begini hasilnya:



Makan ()
def Eat(self):
    while True:
        sleep(4)
        if len([i for i in self.OBJECTS if i["name"] == "meat"]) < 10:
            self.SpawnEat()
        sleep(1)
        self.MinimizeHungry()




Fungsi Start()untuk memulai loop utama:



Mulailah ()
def Start(self):
    while True:  
        self.CheckAll()
        self.DrawAll()
        sleep(0.01)




Dan fungsi run()yang meluncurkan seluruh game.



Lari ()
def run(self):
    proc1 = threading.Thread(target=self.Start)
    proc1.start()
    proc2 = threading.Thread(target=self.Eat)
    proc2.start()




Proses makannya sendiri, saya terapkan secara sederhana pada fungsi CheckAll()dan CheckKeysObjects(). Q CheckKeysObjects()Saya memeriksa untuk melihat apakah pemain menekan tombol E. Jika ditekan, kemudian menempatkan variabel self.PRESS_Edi True.



Dalam loop CheckAll(), saya memeriksa apakah objek saat ini dalam loop adalah formakanan, jika makanan kemudian memeriksa apakah pemain bertabrakan dengannya, jika bertabrakan, kemudian memeriksa variabelnya self.PRESS_E, dan jika itu Truehanya menghapus objek dan meningkatkan rasa lapar, mis. variabel self.PLAYER["hungry"].



Beginilah caranya di dalam kode
for object_now in range(len(self.OBJECTS)):
    ....
    if self.OBJECTS[object_now]["name"] == "meat":
        items_objects.append(object_now)
        is_clash = self.IsClash(
            x=self.OBJECTS[object_now]["x"],
            y=self.OBJECTS[object_now]["y"],
            h=self.OBJECTS[object_now]["h"],
            w=self.OBJECTS[object_now]["w"],
            x2=self.PLAYER["x"],
            y2=self.PLAYER["y"],
            h2=self.PLAYER["h"],
            w2=self.PLAYER["w"],
        )

        if is_clash:
            if self.PRESS_E:
                try:
                    self.PLAYER["hungry"] += self.HUNGRUY_ADD
                    del self.OBJECTS[object_now]
                    break

                except IndexError:
                    pass




Saya akan katakan sebelumnya, saya perlu menulis ulang semua ini ketika saya melakukan inventarisasi


Membuat inventaris



Jadi, sulit, kita perlu membuat inventaris.



Kesulitannya adalah bahwa semua objek perlu ditampilkan, disimpan sejarah, dihapus, objek ditempatkan di lantai.



Saya mulai dengan menambahkan kunci baru ke pemain, yaitu self.PLAYER["inventory"], 4 sel disimpan di sana, seperti ini:



"inventory":{
    "0":{"status":"space","name":"#0", "minimize_image":"#0"},
    "1":{"status":"space","name":"#1", "minimize_image":"#1"},
    "2":{"status":"space","name":"#2", "minimize_image":"#2"},
    "3":{"status":"space","name":"#3", "minimize_image":"#3"},
}


Apakah hanya nomor sel.



status- kunci ini menyimpan nilai apakah sel telur kosong atau tidak. Jika kosong maka "spasi", jika ada item, maka nama item tersebut disimpan di sana.



name- menyimpan nama item, itu akan digunakan saat pemain meletakkan item tersebut.



minimize_image- ini adalah gambar kecil dari item yang ditampilkan di inventaris pemain.



Setelah, saya membuat cek baru di milik kami CheckKeysObjects(), ketika Anda mengklik Xitem, itu akan melemparkannya ke tanah, dan juga ketika Anda mengklik tombol, Efungsi akan dipanggil self.UseEat(), yang sekarang akan kita analisis.



Jadi fungsinyaself.UseEat()adalah jalan melalui semua sel dari persediaan, untuk mencari makanan, dan jika makanan ditemukan, maka itu dikeluarkan dari persediaan, dan 10 unit ditambahkan ke kelaparan. Untuk menghapus item dari inventaris, saya membuat fungsi self.DestroyItem()di mana indeks sel disediakan, dan seluruh sel menjadi kosong secara default dan tanpa apa pun.



self.DestroyItem ()
def DestroyItem(self,index_item: str):
    item = self.PLAYER["inventory"][index_item]
    self.PLAYER["inventory"][index_item] = self.PLAYER["default_inventory_item"](index_item)
    self.PLAYER["inventory_must_update"] = True
    return item




self.CheckKeysObjects ()
def CheckKeysObjects(self):
    self.WALK_LEFT_PLAYER = False
    self.WALK_RIGHT_PLAYER = False
    self.WALK_UP_PLAYER = False
    self.WALK_DOWN_PLAYER = False
    if key("a"):
        self.WALK_LEFT_PLAYER = True
    elif key("d"):
        self.WALK_RIGHT_PLAYER = True
    if key("w"):
        self.WALK_UP_PLAYER = True
    elif key("s"):
        self.WALK_DOWN_PLAYER = True
    if key("f"):
        self.KEY_F = True
    else:
        self.KEY_F= False
    if key("e"):
        self.UseEat()




self.UseEat ()
def UseEat(self):
    for inventory_item in range(len(self.PLAYER["inventory"])):
        if self.PLAYER["inventory"][str(inventory_item)]["name"] == "meat":
            if self.PLAYER["hungry"] + self.ADD_HUNGRY_COUNT < 100.0:
                self.PLAYER["hungry"] += self.ADD_HUNGRY_COUNT
                self.DestroyItem(index_item=str(inventory_item))




Selanjutnya adalah fungsi melempar benda ke tanah.



Namun, tidak ada yang rumit, ketika Anda mengklik Xfungsi yang disebut self.QuitItem(), loop for melewati semua sel inventaris, dan jika kuncinya ["status"]tidak sama "space", maka kami menghapus sel ini menggunakan fungsi yang sebelumnya dianggap self.DestroyItem(), dan membuat objek berdasarkan apa yang ada di dalam sel, X dan Y menempatkan pemain seolah-olah dia telah melemparkannya ke sampingnya.



self.Quititem ()
def QuitItem(self):
    for inventory_item in range(len(self.PLAYER["inventory"])):
        if self.PLAYER["inventory"][str(inventory_item)]["status"] != "space":
            self.CreateObject(
                img=self.PLAYER["inventory"][str(inventory_item)]["img"],
                x=self.PLAYER["x"],
                y=self.PLAYER["y"],
                name=self.PLAYER["inventory"][str(inventory_item)]["name"],
                data=self.PLAYER["inventory"][str(inventory_item)]["data"],
            )
            self.DestroyItem(index_item=str(inventory_item))
            break




Namun semua, banyak hal yang tidak saya katakan bagaimana saya melakukannya, T.K. mereka bukan bagian utama dari permainan, meskipun menarik. Misalnya pesan tentang kemungkinan mengambil barang atau tidak (saat persediaan penuh), saya menambahkan animasi jalan kaki, membuat perpustakaan gambar tersendiri, dan lain-lain.



Itu saja?



Tidak, saya akan menambahkan jaringan saraf ke dalam game, menggunakan perpustakaan yang saya tulis dengan Python,

saya akan membuat interaksi pemain dengan NPC yang dilengkapi dengan jaringan saraf, sebuah

plot kecil, tetapi semacam, dan juga beberapa persediaan untuk pemain, seperti baju besi, makanan. item, kemampuan untuk membangun balok.



Coba permainannya



Anda dapat dengan bebas mendownloadnya dari GitHub saya, Anda hanya perlu Python3 untuk menjalankannya, dan pustaka keyboard . Anda perlu menjalankan file tersebut main.py.



Permainan



All Articles