Untitled
unknown
plain_text
a year ago
40 kB
8
Indexable
import pygame from pygame.locals import * import random import time import socket import threading pygame.init() s = socket.socket() host = "127.0.0.1" port = 9999 playerOne = 1 playerTwo = 2 bottomMsg = "" currentPlayer = 0 msg ="" ################################################ SET UP BẢNG TÍNH ĐIỂM SAU TRẬN ĐẤU ######################################################################### def writeScorefile(): # mô tả về việc tạo ra một tệp ''' Để bắt đầu, nhóm sẽ kiểm tra xem có tệp điểm số nào tồn tại bằng cách thử mở nó. Nếu không thể mở tệp, cho thấy tệp đó không tồn tại, nhóm sẽ tạo một tệp mới. Trong trường hợp này, tệp mới sẽ được tạo ra và được đặt tiêu đề như "Tên Người Chơi, Điểm Số". Nếu tệp điểm số đã tồn tại, quá trình kiểm tra sẽ kết thúc. ''' haveOne = False try: #Chương trình sẽ mở tệp tin này open('ProJect_Pygame_Nhom18/BangBang/Tank2P/BangTinhDiem.txt', 'r') haveOne = True finally: if not haveOne: #Nếu không có tệp tin, chương trình sẽ tạo một tệp mới scores = open('BangTinhDiem.txt', 'w') scores.write('Player1: 0' + '\n') scores.write('Player2: 0' + '\n') scores.close() scoredata = {} ''' Chương trình sẽ mở tệp 'BangTinhDiem.txt', sau đó ghi hai dòng vào tệp, mỗi dòng chứa số thứ tự và điểm số cách nhau bởi dấu phẩy. Sau khi ghi, tệp sẽ được đóng và một từ điển rỗng có tên là scoredata sẽ được khởi tạo để lưu trữ dữ liệu. ''' ############################################## SET UP CHỈ SỐ TANK #################################################################################################### def player_classes(option,player): ''' Để thêm thuộc tính vào player.sprite dựa trên loại xe tăng mà người dùng đã chọn (player1 hoặc player2), chương trình sẽ kiểm tra loại xe tăng đó và thêm các thuộc tính tương ứng. Điều này sẽ giúp xác định các đặc điểm cụ thể của từng loại xe tăng và áp dụng chúng vào sprite của người chơi. ''' if option == 0: #tank 1 có tốc độ bắn và di chuyển nhanh hơn, nhưng có lượng máu thấp hơn player.cooldown = 30 #Giảm cooldown để bắn nhanh hơn player.health = 3 player.speed = 5 player.pics = ver1 # ảnh dùng cho xe tăng loại 1 player.image = ver1[0] # Ảnh hiển thị đầu tiên cho xe tăng loại 1 elif option == 1: #tank 2 có tốc độ bắn và di chuyển chậm, nhưng nhiều máu player.cooldown = 45 player.health = 6 player.speed = 3 player.pics = ver2 player.image = ver2[0] ############### SET UP DI CHUYỂN CỦA TANK ####################### def movement(player): ''' di chuyển trong trò chơi phụ thuộc vào phím được bấm xử lý đầu vào từ bàn phím để di chuyển tank theo các hướng, ngăn tank đi xuyên tường, đi xuyên player khác ''' key = pygame.key.get_pressed() #tạo ra một cơ chế di chuyển liên tục cho sprite mà không bị gián đoạn khi người chơi giữ phím #đồng thời đề cập đến cách xử lý va chạm để ngăn sprite không di chuyển qua các vật thể khác. if key[player.keys[0]]: player.rect.left -= player.speed # Di chuyển sprite sang trái theo tốc độ đã định player.direction = 'left' # Cập nhật hướng di chuyển của sprite player.image = player.pics[3] # Cập nhật hình ảnh của sprite khi người chơi hướng di chuyển sang trái elif key[player.keys[1]]: player.rect.left += player.speed player.direction = 'right' player.image = player.pics[2] elif key[player.keys[2]]: player.rect.top -= player.speed player.direction = 'up' player.image = player.pics[0] elif key[player.keys[3]]: player.rect.top += player.speed player.direction = 'down' player.image = player.pics[1] if len(pygame.sprite.spritecollide(player,players,False))> 1 or pygame.sprite.spritecollide(player,walls,False): #Trong trường hợp "player" nằm trong nhóm sprite "players", chúng ta cần kiểm tra xem có va chạm với đối tượng khác trong nhóm hay không bằng cách xem độ dài của danh sách va chạm có lớn hơn 1 không. Nếu độ dài này lớn hơn 1, điều này có nghĩa là đã có va chạm với một "player" khác. #Hàm collidelist sẽ trả về -1 nếu không có va chạm nào. Vì vậy, nếu giá trị trả về khác -1, điều đó cho biết "player" đã va chạm vào 1 khối tuong. if player.direction == 'left': player.rect.left += player.speed if player.direction == 'right': player.rect.left -= player.speed if player.direction == 'up': player.rect.top += player.speed if player.direction == 'down': player.rect.top -= player.speed ################################### SET UP VỊ TRÍ MÁU CỦA PLAYER TRONG TRẬN CHIẾN ############################################################################### def drawPlayerHealth(player): #Hàm này cập nhật và in số máu của người chơi khi ở chế độ chiến đấu ''' Sử dụng vòng lặp for dựa trên lượng máu còn lại của người chơi để in trái tim. - Vị trí của trái tim thay đổi tùy theo người chơi, - Nếu là người chơi 1, trái tim in ở góc dưới bên trái. - Nếu là người chơi 2, trái tim in ở góc dưới bên phải. ''' healthimage = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/blood.png') p1healthpos = [60, 500] #set up vị trí máu của Player1 trong trận chiến p1title = my_font4.render('P1', True, (0,0,0)) #tạo tiêu đề "chữ P1" với màu tương ứng p2healthpos = [520,500] p2title = my_font4.render('P2', True, (0,0,255)) screen.blit(p1title, (35, 500)) # vị trí chữ P1 (góc dưới bên trái màn hình) screen.blit(p2title, (495, 500)) # Khi giá trị của tọa độ x tăng, đối tượng di chuyển sang bên phải; tọa độ y tăng,di chuyển xuống dưới. #duyệt số lượng máu của người chơi và hiển thị nó trên màn hình tương ứng với vị trí của người chơi 1 hoặc người chơi 2 #đồng thời cập nhật vị trí kế tiếp để hiển thị hình ảnh máu tiếp theo for c in range(player.health): if player == player1: screen.blit(healthimage,p1healthpos) p1healthpos[0] += 15 else: screen.blit(healthimage, p2healthpos) p2healthpos[0] += 14 ''' Khi player là player1, máu được in tại vị trí p1healthpos trên màn hình. Việc tăng tọa độ x của p1healthpos lên 15 cho mỗi cục máu đảm bảo không có chồng lấn giữa các biểu tượng máu. ''' ############################################ SET UP ĐẠN ############################################################### def bullet(player): #Hàm tạo đạn, thiết lập kích thước, màu sắc, và vị trí của đạn. ''' Hàm sẽ tạo ra đạn khi người chơi bắn, dựa vào người chơi là player 1 hoặc 2. Đạn sẽ được tạo ra và bay ra khỏi tank ''' bullet = pygame.sprite.Sprite() bullet.image = pygame.Surface((5,5)) #kích thước viên đạn bullet.image.fill((255,0,0)) #màu viên đạn bullet.rect = pygame.Rect(bullet.image.get_rect()) #tạo hình (Rect) cho đối tượng bullet dựa trên kích thước của bullet.image, xác định vị trí và kích thước của đối tượng bullet bullet.direction = player.direction #set up vị trí của viên đạn sao cho khi bắn ra nó nằm ở giữa nòng súng tank if bullet.direction == 'up': bullet.rect.x, bullet.rect.y = player.rect.x + 12, player.rect.y - 20 elif bullet.direction == 'down': bullet.rect.x, bullet.rect.y = player.rect.x + 12, player.rect.y + 24 elif bullet.direction == 'left': bullet.rect.x, bullet.rect.y = player.rect.x - 20, player.rect.y + 12 elif bullet.direction == 'right': bullet.rect.x, bullet.rect.y = player.rect.x + 24, player.rect.y + 12 bulletgroup.add(bullet) def bullet_update(): #cập nhật vị trí của đạn ''' viên đạn di chuyển theo hướng tương ứng với thuộc tính direction của nó khi viên đạn được bắn ra. ''' for bullet in bulletgroup: if bullet.direction == 'left': bullet.rect.x -= 6 elif bullet.direction == 'right': bullet.rect.x += 6 elif bullet.direction == 'up': #Khi viên đạn di chuyển lên trên, nghĩa là nó đang đi ngược với trục y của màn hình, do đó để viên đạn di chuyển lên trên, giá trị của trục y cần phải giảm bullet.rect.y -= 6 elif bullet.direction == 'down': bullet.rect.y += 6 ######################################## SET UP MAP ####################################################################### def readMap(): ''' chọn một map từ tệp, đọc và phân tích từng dòng của nó, nơi mỗi ô trong tệp cách nhau bởi dấu phẩy,dấu chấm ('.') đại diện cho các tile (tường) Khi đọc mỗi ô, phương pháp này gán hình ảnh tường cho mỗi ô và có thể tiến hành chỉnh sửa ô nếu cần thiết ''' Map = open(random.choice(maps), 'r') #Mở một file bản đồ ngẫu nhiên từ danh sách maps với quyền đọc ('r'). x = 0 # kiểm soát vị trí x và y trên bản đồ khi đặt các tiles y = 0 ''' tạo ra một bức tường từ các tiles có kích thước 12x12 pixel, biểu diễn bởi các dấu chấm trong tệp đầu vào. ''' for l in Map: builtup = l.split(',') #Tách dòng hiện tại thành một list builtup bằng cách phân chia theo dấu phẩy builtup[-1] = builtup[-1].strip('\n') # Loại bỏ ký tự xuống dòng ở cuối mỗi dòng trong list builtup. for D in builtup: if D == '.': tile = pygame.sprite.Sprite() tile.image = tiles tile.rect = pygame.Rect(x, y, 12, 12) walls.add(tile) y += 12 #Tăng y sau mỗi tile và di chuyển để đặt tile tiếp theo theo chiều dọc. else: # Nếu phần tử không phải là dấu chấm, chỉ tăng y và không tạo sprite y += 12 x += 11 y = 0 Map.close() ################################## SET UP MENU GAME ############################################################################# def gameMenu(thisStage): ''' cải thiện menu game bằng cách đặt nền nhạc, và hiển thị tiêu đề cùng với hai lựa chọn: "Start Game" và "Exit Game". Khi người chơi di chuyển chuột qua các label lựa chọn, chúng sẽ được làm nổi bật với màu sắc và dấu gạch dưới. Phản ứng của label được cập nhật trực tiếp trên màn hình. Sự kiện chuột được quản lý để xử lý việc bắt đầu game hoặc thoát khỏi game phụ thuộc vào label mà người dùng chọn. ''' global run, selecting, battling, end pygame.mixer.music.load(musicList[0]) pygame.mixer.music.set_volume(0.4) pygame.mixer.music.play(-1) Title = my_font.render('Tank PvP', True, (255, 0, 0)) # set up tiêu đề game màu đỏ #tạo hình chữ nhật (text_rect) xung quanh Title, canh giữa theo chiều ngang ở trên màn hình dọc, làm Title nổi bật. text_rect = Title.get_rect(center=(screen.get_width() / 2, screen.get_height() / 4)) # in dòng chữ lên màn hình screen.blit(Title, text_rect) Start_label = my_font2.render('Start Game', True, (212,212,212)) #Tạo surface chứa văn bản "Start Game", tham số True giúp hình ảnh rõ nét hơn Exit_label = my_font2.render('Exit Game', True, (212,212,212)) Srect = Rect(210,280,421,339) #hiệu ứng khi trỏ chuột vào Erect = Rect(245,340,380,430) while thisStage: x, y = pygame.mouse.get_pos() #định vị trí của chuột trên màn hình Opt = 0 ''' Nếu vị trí chuột (x, y) nằm trong phạm vi của hình chữ nhật Srect tức là vùng mà label "Start Game", "Exit Game" ''' if Srect[0] < x <Srect[2] and Srect[1] < y < Srect[3]: my_font2.set_underline(True) Start_label = my_font2.render('Start Game', True, (255,255,0)) # nháy màu vàng, phần gạch chân cũng vậy screen.blit(Start_label, (183,280)) pygame.display.flip() Opt = 1 #biến Opt được đặt thành 1, label "Start Game" đang được chọn. Khi người chơi nhấp chuột, có thể sẽ có sự kiện diễn ra tùy vào giá trị của Opt. elif Erect[0] < x < Erect[2] and Erect[1] < y < Erect[3]: my_font2.set_bold(True) Exit_label = my_font2.render('Exit Game', True, (255,0,0)) screen.blit(Exit_label, (170, 340)) pygame.display.flip() Opt = 2 my_font2.set_bold(False) #tắt hiệu ứng gạch dưới my_font2.set_underline(False) Start_label = my_font2.render('Start Game', True, (212,212,212)) #set up màu cho label Star Game Exit_label = my_font2.render('Exit Game', True, (212,212,212)) screen.blit(screenPIC, (0,0)) screen.blit(Title, (90,120)) # căn giữa Tank2P screen.blit(Start_label, (180,280)) #tọa độ chuỗi Start Game screen.blit(Exit_label, (180, 340)) #blit: viết nội dung lên screen pygame.display.flip() #cập nhật nội dung trên screen for ev in pygame.event.get(): if ev.type == QUIT: pygame.mixer.music.stop() #khi đóng cửa sổ game thì hàm được gọi để stop nhạc nền của game run = False starting = False selecting = False battling = False #các biến cục bộ được trả về false để kết thúc các trạng thái end = False thisStage = False elif ev.type == MOUSEBUTTONDOWN: #kích hoạt event khi click chuột if Opt == 1: pygame.mixer.music.stop() starting = False #nếu chọn Start game thì nhạc sẽ dừng, kiểm soát hiển thị trên màn và chuyển tiếp vào select tank thisStage = False elif Opt == 2: pygame.mixer.music.stop() run = False starting = False selecting = False battling = False #nếu chọn exit game thì nhạc cũng dừng lại và đóng cửa sổ, kết thúc mọi trạng thái end = False thisStage = False def create_thread(target): t = threading.Thread(target = target) #argument - target function t.daemon = True t.start() def selectionScreen(thisStage): global msg #shows menu, cửa sổ màn hình đầu tiên khi vào gaem ''' Đoạn mã cần kiểm tra biến 'thisStage' trước khi thực thi một số chức năng như cập nhật lớp của "player tank" và gọi hàm readMap() để chuẩn bị cho trận chiến. ''' global run, selecting, battling, end #biến toàn cục cho phép thay đổi trong phạm vi cục bộ của hàm pygame.mixer.music.load(musicList[1]) # chỉ số [1] cho biết rằng nó đang tải bản nhạc thứ hai trong danh sách pygame.mixer.music.set_volume(0.4) #mức âm lượng được set up ở mức 40% pygame.mixer.music.play(-1) #phát nhạc mãi mãi, nếu hết nhạc thì phát lại tiếp Opt1 = 0 Opt2 = 0 #Opt1 - Opt2 các cài đặt của player1 - player2 instructionP1 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/moveP2.png') #bảng hướng dẫn điều khiển tank instructionP2 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/moveP1.png') Title = my_font3.render('Select Tank', True, (9,255,242)) Title2 = my_font4.render('Waiting for player', True, (9,255,242)) # Lấy hình chữ nhật bao quanh văn bản Title_rect = Title.get_rect() # Canh lề giữa cho văn bản Title_rect.centerx = screen.get_rect().centerx # in văn bản lên màn hình screen.blit(Title, Title_rect) p1Title = my_font4.render('P1', True, (255,255,0)) #chữ màu vàng nền trong suốt p2Title = my_font4.render('P2', True, (255,255,0)) instruction = my_font4.render('Use your left and right controls to switch between tanks.', True, (255,255,0)) instruction2 = my_font4.render('Press ENTER to start the battle !!!', True, (255,255,0)) options = [imageUp_v1,imageUp_v2] #tạo danh sách chứa các ảnh của 2 phiên bản tank stats = {0:['3', '6', '3'], 1:['6','3','1']} DisplaySurf = pygame.Surface((80,80)) DisplaySurf.fill((255,212,255)) #tạo ô nền cho tank DisplaySurf2 = pygame.Surface((80,80)) DisplaySurf2.fill((255,212,255)) def receive_msg(): global msg while True: try: time.sleep(0.5) recvData = s.recv(2048 * 10) msg = recvData.decode() print("Receive form "+str(currentPlayer)+" :", msg) except socket.error as e: print("Socket connection error:", e) break try: s.connect((host, port)) print("Connected to :", host, ":", port) recvData = s.recv(2048 * 10) bottomMsg = recvData.decode() if "1" in bottomMsg: currentPlayer = 1 print( "You are player 1") Title2 = my_font4.render('You are player 1', True, (9,255,242)) screen.blit(Title2, (170, 120)) # tọa độ dòng chữ Select Tank else: currentPlayer =2 print( "You are player 1") Title2 = my_font4.render('You are player 2', True, (9,255,242)) screen.blit(Title2, (170, 120)) # tọa độ dòng chữ Select Tank # s.close() except socket.error as e: print("Socket connection error:", e) create_thread(receive_msg) while thisStage: for ev in pygame.event.get(): if ev.type == QUIT: pygame.mixer.music.stop() run = False selecting = False battling = False end = False thisStage = False s.close() elif ev.type == KEYDOWN: if ev.key == K_RETURN: #Khi nhấn phím ENTER, dừng âm nhạc, gọi hàm readMap() để tải bản đồ, sau đó gọi hàm player_classes() với Opt1 và player1, rồi Opt2 và player2; thiết lập selecting và thisStage thành False để chuyển sang giai đoạn khác. pygame.mixer.music.stop() readMap() player_classes(Opt1, player1) player_classes(Opt2, player2) selecting = False thisStage = False if currentPlayer == 1: if ev.key == K_a: data = "A"+str(currentPlayer) print("A") # đối với player1 sử dụng phím A or D để lựa chọn tank if Opt1 == 0: Opt1 = 1 else: Opt1 -= 1 s.sendall(data.encode('utf-8')) elif ev.key == K_d: print("D") data = "D"+str(currentPlayer) if Opt1 == 1: Opt1 = 0 else: Opt1 += 1 s.sendall(data.encode('utf-8')) else : if ev.key == K_a: print("A") data = "A"+str(currentPlayer) # đối với player2 sử dụng phím A or D để lựa chọn tank if Opt2 == 0: Opt2 = 1 else: Opt2 -= 1 s.sendall(data.encode('utf-8')) elif ev.key == K_d: print("D") data = "D"+str(currentPlayer) if Opt2 == 1: Opt2 = 0 else: Opt2 += 1 s.sendall(data.encode('utf-8')) if msg == "": break if "A" in msg: if currentPlayer == 1: print("Player "+ str(currentPlayer)+" di chuyen ",msg ) screen.blit(options[1], (415, 220)) instruction = my_font4.render('User 2 click A', True, (255,255,0)) msg = "" else: print("Player "+ str(currentPlayer)+" di chuyen ",msg ) screen.blit(options[0], (415, 220)) instruction = my_font4.render('User 1 click A', True, (255,255,0)) msg = "" if "D" in msg: if currentPlayer == 1: print("Player "+ str(currentPlayer)+" di chuyen ",msg ) screen.blit(options[1], (415, 220)) instruction = my_font4.render('User 2 click D', True, (255,255,0)) msg = "" else: print("Player "+ str(currentPlayer)+" di chuyen ",msg ) screen.blit(options[0], (415, 220)) instruction = my_font4.render('User 1 click D', True, (255,255,0)) msg = "" p1statsHealth = my_font5.render('Health: ' + stats[Opt1][0], True, (255,212,212)) p1statsSpeed = my_font5.render('Speed: ' + stats[Opt1][1],True, (255,212,212)) p1statsReload = my_font5.render('Reload: ' + stats[Opt1][2], True, (255,212,212)) #these renders needs to be in the loop because as users switch p2statsHealth = my_font5.render('Health: ' + stats[Opt2][0], True, (255,212,212)) #between tanks, the stats info needs to update p2statsSpeed = my_font5.render('Speed: ' + stats[Opt2][1],True, (255,212,212)) p2statsReload = my_font5.render('Reload: ' + stats[Opt2][2], True, (255,212,212)) screen.blit(screenPIC, (0,0)) screen.blit(Title, (170, 70)) # tọa độ dòng chữ Select Tank screen.blit(Title2, (170, 120)) # tọa độ dòng chữ Select Tank screen.blit(p1Title, (160, 150)) screen.blit(p2Title, (420, 150)) screen.blit(p1statsHealth, (45,200)) screen.blit(p1statsSpeed, (45,220)) screen.blit(p1statsReload, (45,240)) screen.blit(p2statsHealth, (500,200)) #tọa độ chỉ số máu của player2 screen.blit(p2statsSpeed, (500,220)) #tọa độ chỉ tốc độ của player2 screen.blit(p2statsReload, (500,240)) #tọa độ chỉ số tốc độ bắn của player2 screen.blit(DisplaySurf, (135, 189)) #tọa độ ô trắng screen.blit(DisplaySurf2, (390, 189)) screen.blit(options[Opt1], (160, 220)) # tọa độ hình tank trong ô màu trắng screen.blit(options[Opt2], (415, 220)) screen.blit(instructionP1, (70, 290)) screen.blit(instructionP2, (330, 290)) screen.blit(instruction, (70, 500)) #tọa độ của dòng chữ "Use your left and right controls..." screen.blit(instruction2, (170, 520)) pygame.display.flip() ################################# SET UP TRẬN ĐẤU ######################################################################## import math # Hàm tính khoảng cách giữa hai điểm def distance(point1, point2): return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2) def battleScreen(thisStage): ''' quản lý màn hình chiến đấu trong game bằng cách xử lý các sự kiện, di chuyển, cập nhật trạng thái đạn, xử lý va chạm, và hiển thị các đối tượng trên màn hình, kết thúc trò chơi khi người chơi hết máu. ''' global run, end #biến cục bộ sẽ update các thay đổi của function pygame.mixer.music.load(musicList[2]) pygame.mixer.music.set_volume(0.4) pygame.mixer.music.play(-1) timer = 0 #Khởi tạo biến đếm để điều chỉnh thời gian nghỉ giữa các lần bắn của người chơi timer2 = 0 while thisStage: fps = clock.tick(30) #điều chỉnh fps giúp game mượt hơn timer += 1 #Mỗi vòng lặp, timer và timer2 tăng lên 1, giúp đếm số lần lặp xảy ra và có thể dùng để kiểm soát thời gian nghỉ giữa các lần bắn timer2 += 1 for ev in pygame.event.get(): if ev.type == QUIT: pygame.mixer.music.stop() run = False battling = False thisStage = False end = False movement(player1) #xử lý di chuyển, va chạm (p1-p2-tường) movement(player2) bullet_update() key = pygame.key.get_pressed() #kiêmr tra các phím được nhấn #Khi người chơi nhấn phím bắn sau hết thời gian cooldown của lần bắn trước, hệ thống sẽ phát âm thanh bắn và tạo viên đạn mới cho người chơi đó #Bộ đếm thời gian (timer cho người chơi 1 và timer2 cho người chơi 2) sẽ được đặt lại về 0 để chuẩn bị cho lần bắn tiếp theo if key[player1.keys[4]]: if timer >= player1.cooldown: shoot.play() bullet(player1) timer = 0 if key[player2.keys[4]]: if timer2 >= player2.cooldown: shoot.play() bullet(player2) timer2 = 0 for bullets in bulletgroup: if pygame.sprite.collide_rect(bullets,player1): #check viên đạn có trúng p1 không bulletgroup.remove(bullets) player1.health -= 1 explode.play() #phát âm thanh vuno screen.blit(explosion, player1.rect) #in hình ảnh vuno tại vị trí p1 pygame.display.flip() #update screen để hiển thị hình ảnh vuno time.sleep(1) # Tìm vị trí respawn cách xa player2 nhất, để lúc random lại vị trí nó không đứng gần player cũ farthest_point = max(spawnpoints, key=lambda point: distance(point, player2.rect.center)) player1.rect.center = farthest_point if pygame.sprite.collide_rect(bullets,player2): bulletgroup.remove(bullets) player2.health -= 1 explode.play() screen.blit(explosion, player2.rect) pygame.display.flip() time.sleep(1) # Tìm vị trí respawn cách xa player1 nhất farthest_point = max(spawnpoints, key=lambda point: distance(point, player1.rect.center)) player2.rect.center = farthest_point if pygame.sprite.spritecollide(bullets,walls,False): explode.play() bulletgroup.remove(bullets) if len(pygame.sprite.spritecollide(bullets,bulletgroup, False))>1: pygame.sprite.spritecollide(bullets,bulletgroup, True) screen.blit(background, (0,0)) #in background đè lên toàn bộ screen walls.draw(screen) players.draw(screen) bulletgroup.draw(screen) #các viên đạn được bắn ra drawPlayerHealth(player1) drawPlayerHealth(player2) pygame.display.flip() pygame.display.update() if player1.health == 0 or player2.health == 0: #nếu 1 trong 2 player hết sạch máu thì kết thúc trò chơi,màn hình kết thúc sẽ hiển thị kết quả tỉ số pygame.mixer.music.stop() battling = False thisStage = False endScreen(end) ########################### SET UP MÀN HÌNH CUỐI - KHI TRẬN CHIẾN KẾT THÚC ########################################################### def endScreen(thisStage): ''' xác định người chiến thắng, tính điểm, hiển thị màn hình kết thúc và kết thúc trò chơi. ''' global run, starting, selecting pygame.mixer.music.load(musicList[3]) pygame.mixer.music.set_volume(0.4) pygame.mixer.music.play(-1) bulletgroup.empty() walls.empty() #đọc từng dòng của tệp tin và tách dữ liệu bằng dấu phẩy (,) để lấy ra thông tin điểm số scores = open('ProJect_Pygame_Nhom18/BangBang/Tank2P/BangTinhDiem.txt', 'r') for l in scores: dataFields = l.split(':') dataFields[-1] = dataFields[-1].strip('\n') scoredata[dataFields[0]] = int(dataFields[1]) #dictionary chứa các điểm số, key là thông tin được đọc từ tệp và value được chuyển thành số nguyên scores.close() winner = max(player1.health,player2.health) #người chơi nào hết sạch máu sau trận chiến thì người đó thua if winner == player1.health: WinnerTitle = my_font2.render('PLAYER 1 WINS', True, (255,255,0)) scoredata['Player1'] +=1 # =1 điểm cho người chơi thắng else: WinnerTitle = my_font2.render('PLAYER 2 WINS', True, (255,255,0)) scoredata['Player2'] +=1 # mở tệp trong chế độ ghi (mode 'w': write), ghi điểm số được cập nhật của cả hai người chơi và sau đó đóng tệp. scores = open('ProJect_Pygame_Nhom18/BangBang/Tank2P/BangTinhDiem.txt', 'w') scores.write('Player1,' + str(scoredata['Player1']) + '\n') scores.write('Player2,' + str(scoredata['Player2']) + '\n') scores.close() Title = my_font3.render('END OF THE MATCH', True, (255,0,0)) scoreTitle = my_font2.render('Scores', True, (255,212,255)) instruction = my_font4.render('Press R to reset scores!', True, (255,255,0)) instruction2 = my_font4.render('Press ENTER to return to game menu.', True, (255,255,0)) while thisStage: p1Scores = my_font2.render('Player 1: ' +str(scoredata['Player1']), True, (9,255,212)) p2Scores = my_font2.render('Player 2: '+ str(scoredata['Player2']), True, (9,255,212)) #set up tọa độ vị trí căn lề cho các text screen.blit(screenPIC, (0,0)) screen.blit(Title, (60,50)) screen.blit(WinnerTitle, (145,200)) screen.blit(scoreTitle, (240,280)) screen.blit(p1Scores, (50,340)) screen.blit(p2Scores, (340,340)) screen.blit(instruction, (210, 480)) screen.blit(instruction2, (150,500)) pygame.display.flip() for ev in pygame.event.get(): if ev.type == QUIT: pygame.mixer.music.stop() run = False end = False thisStage = False elif ev.type == KEYDOWN: if ev.key == K_RETURN: pygame.mixer.music.stop() thisStage = False elif ev.key == K_r: scoredata['Player1'] = 0 #nhấn phím R để reset bảng điểm scoredata['Player2'] = 0 scores = open('ProJect_Pygame_Nhom18/BangBang/Tank2P/BangTinhDiem.txt', 'w') scores.write('Player1: ' + str(scoredata['Player1']) + '\n') scores.write('Player2: ' + str(scoredata['Player2']) + '\n') #update kết quả trong fie txt scores.close() starting = True selecting = True pygame.init() pygame.mixer.init(44100, -16, 2, 2048) #set up chất lựơng âm thanh clock = pygame.time.Clock() #điều chỉnh tốc độ của trò chơi, thời gian chờ,... colours = pygame.color.THECOLORS # dictionary chứa màu sắc tiêu chuẩn của Pygame my_font = pygame.font.SysFont('Verdana', 100) my_font2 = pygame.font.SysFont('moolboran', 66) my_font3 = pygame.font.SysFont('andalus', 72) #setup Font chữ my_font4 = pygame.font.SysFont('candara', 20) my_font5 = pygame.font.SysFont('arial', 16) size = (605, 540) #kích thước cửa sổ game screen = pygame.display.set_mode(size) screenPIC = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/anhnen.png') pygame.display.set_caption("Tank Moba PvP") #đặt tiêu đề cửa sổ game background = pygame.Surface(size) # tạo một đối tượng Surface để làm nền, sau đó "convert" nó để cải thiện hiệu suất hiển thị trên màn hình. background = background.convert() background.fill(colours['grey']) #màu nền của map trong game explode = pygame.mixer.Sound('ProJect_Pygame_Nhom18/BangBang/Tank2P/bum.ogg') shoot = pygame.mixer.Sound('ProJect_Pygame_Nhom18/BangBang/Tank2P/music/fireMusic.mp3') musicList = ['ProJect_Pygame_Nhom18/BangBang/Tank2P/music/endMusic.mp3','ProJect_Pygame_Nhom18/BangBang/Tank2P/music/selectSong.mp3','ProJect_Pygame_Nhom18/BangBang/Tank2P/mbattle.ogg','ProJect_Pygame_Nhom18/BangBang/Tank2P/music/endMusic.mp3'] maps = ['ProJect_Pygame_Nhom18/BangBang/Tank2P/map1.txt', 'ProJect_Pygame_Nhom18/BangBang/Tank2P/map2.txt', 'ProJect_Pygame_Nhom18/BangBang/Tank2P/map3.txt'] tiles = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tuong.png') explosion = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/vuno.png') imageUp_v1 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tank1 up.png') imageDown_v1 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tank1 down.png') imageRight_v1 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tank1 right.png') #load ảnh khi tank thay đổi hướng khi di chuyển imageLeft_v1 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tank1 left.png') imageUp_v2 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tank2 up.png') imageDown_v2 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tank2 down.png') imageRight_v2 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tank2 right.png') imageLeft_v2 = pygame.image.load('ProJect_Pygame_Nhom18/BangBang/Tank2P/picture/tank2 left.png') #Hai danh sách chứa hình ảnh đại diện cho các version khác nhau của người chơi và các nhiều hướng khác nhau ver1 = [imageUp_v1,imageDown_v1,imageRight_v1,imageLeft_v1] ver2 = [imageUp_v2,imageDown_v2,imageRight_v2,imageLeft_v2] spawnpoints = [(30,30),(40,390),(560,130),(560,390)] #List chứa các cặp tuple, mỗi tuple là một điểm xuất phát của viên đạn trên màn hình. players = pygame.sprite.Group() #Tạo hai đối tượng người chơi là các sprite có hình chữ nhật xác định vị trí và kích thước, hướng di chuyển trên màn hình player1 = pygame.sprite.Sprite() player1.rect = pygame.Rect((20, 20),(24,24)) player1.direction = 'up' player1.keys = (K_a, K_d, K_w, K_s,K_4) # Player 1 sử dụng phím W A S D để di chuyển và phím bắn đạn là phím 4 player2 = pygame.sprite.Sprite() player2.rect = pygame.Rect((560, 390), (24,24)) player2.direction = 'up' player2.keys = (K_LEFT, K_RIGHT, K_UP, K_DOWN,K_l) # Player 2 sử dụng phím LEFT RIGHT UP DOWN để di chuyển và phím bắn đạn là phím l players.add(player1) #phương thức add thêm player 1 & 2 vào nhóm player players.add(player2) bulletgroup = pygame.sprite.Group() walls = pygame.sprite.Group() run = True starting = True selecting = True battling = True end = True writeScorefile() #ghi điểm số ra tệp txt scoredata = {} #Khởi tạo một dictionary rỗng để ưu trữ dữ liệu điểm số while run: fps = clock.tick(30) gameMenu(starting) # hàm hiển thị menu trò chơi khi trò chơi bắt đầu selectionScreen(selecting) #hiển thị màn hình chọn tank battleScreen(battling) pygame.display.quit() quit()
Editor is loading...
Leave a Comment