If you want to see how the things you make this time work, please see here (youtube video). I think that the video will explain more deeply than the explanation here.
This time, I used the free Sound effects and BGM. Also, when using sound effects in pygame, it must be a wav file, so here I converted from mp3 to wav.
Please see Github because it will be long if you put the whole code. Here, we will explain each function one by one.
First, import the library to be used this time. This time we will use numpy to manipulate the matrix.
library.py
import pygame
from pygame.locals import *
import numpy as np
import tkinter as tk
import random
And this is, as the name implies, a function that draws a field. The field this time is in the shape of a grid. I haven't done much difficult things here, so if you take a closer look, you'll understand. There is also a function called p2_field, but what it does is the same as this function.
battle_ship.py
def p1_field(win):
rows = 10
x = 55
y = 55
sizeBwn = 65
for i in range(rows):
x += sizeBwn
y += sizeBwn
pygame.draw.line(win,(0,0,0),(x,55),(x,705))
pygame.draw.line(win,(0,0,0),(55,y),(705,y))
pygame.draw.line(win,(0,0,0),(55,55),(55,705),5)
pygame.draw.line(win,(0,0,0),(55,55),(705,55),5)
pygame.draw.line(win,(0,0,0),(55,705),(705,705),5)
pygame.draw.line(win,(0,0,0),(705,55),(705,705),5)
drawnumbers(87.5,win)
drawstring(87.5,win)
font = pygame.font.SysFont('comicsens',100)
text = font.render("Your Field",5,(0,0,255))
win.blit(text,(380-text.get_width()/2,730))
This is the last one called in the previous function. It draws numbers and alphabets, but it's almost like a decoration, with little to do with the game.
battle_ship.py
def drawnumbers(pos,win):
for b in num_list:
font = pygame.font.SysFont('comicsens',25)
text = font.render(b,1,(0,0,0))
win.blit(text,(pos - (text.get_width()/2),5))
pos += 65
def drawstring(pos,win):
for i in st_list:
font = pygame.font.SysFont('comicsens',25)
text = font.render(i,1,(0,0,0))
win.blit(text,(5,pos - (text.get_width()/2)))
pos += 65
This is the function that will be called when you are in the position of the ship. This time it will be called first. This uses the same one I introduced to Qiita earlier in How to change only the color of the button pressed in Tkinter. I taught you a simple method, but it didn't work when I drew the ship, so I'll put it on hold.
battle_ship.py
def setting_ships():
column = -1
row = 0
root = tk.Tk()
root.title('Set Your Ships')
root.geometry('470x310')
for i in range(101):
if i > 0:
if i%10 == 1:
row += 1
column = -1
column += 1
text=f'{i}'
btn = tk.Button(root, text=text)
btn.grid(column=column, row=row)
btn.config(command=collback(btn,i))
root.mainloop()
main()
def collback(btn,i):
def nothing():
btn.config(bg='#008000')
numbers.append(i)
return nothing
This is the next function to be called. This draws the field and calls a function called draw_ships.
battle_ship.py
def main():
pygame.display.set_caption("battle ship")
win.fill((255,255,255))
p1_field(win)
p2_field(win)
draw_ships(array_1,numbers)
bomb_buttons()
pygame.quit()
This is draw_ships. The array passed here and the array passed to other functions are the same and are two-dimensional arrays. Here, draw the position of the ship specified in Tkinter on the field. The list called numbers contains the numbers of the buttons you pressed.
battle_ship.py
array_1 = np.zeros([10,10],dtype=int)
array_2 = np.zeros([10,10],dtype=int)
def draw_ships(array, numbers):
width = 65
numbers = np.sort(numbers)
for i in numbers:
array.flat[i-1] = 1
array = array.reshape(-1,1)
for i in np.where(array == 1)[0]:
index = i//10
if i >= 10:
columns = int(str(i)[1:])
else:
columns = i
pygame.draw.rect(win,(0,0,0),(55+width*columns,55+width*index,width,width),0)
pygame.display.update()
ai_ships(array_2)
And this is the next function to be called. Although it is written as ai, this is simply a random installation of ships. You can't see the other ai ship, so just store the ship's position in the array.
battle_ship.py
def ai_ships(array):
num_5 = random.randint(0,5)
num_4_1 = random.randint(8,9)
num_4_2 = random.randint(3,6)
num_3_1 = random.randint(3,6)
num_3_2 = random.randint(5,7)
num_2 = random.randint(2,6)
num_1_1 = random.randint(0,2)
num_1_2 = random.randint(5,9)
if num_5 >= 7:
array[num_5:num_5+5,0] = 1
if num_5 <= 6:
array[-5:,0] = 1
array[num_3_1,num_3_2:num_3_2+3] = 1
array[num_2,2:4] = 1
array[num_4_1,num_4_2:num_4_2+4] = 1
array[num_1_1,num_1_2] = 1
array = array.reshape(-1,1)
pygame.display.update()
Then the game starts and the button is displayed again. Whether or not it was hit by a function called bombing in collback and the subsequent processing are performed.
battle_ship.py
def bomb_buttons():
column = -1
row = 0
root = tk.Tk()
root.title('bombing')
root.geometry('470x310')
for i in range(101):
if i > 0:
if i%10 == 1:
row += 1
column = -1
column += 1
text=f'{i}'
btn = tk.Button(root, text=text)
btn.grid(column=column, row=row)
btn.config(command=collback2(btn,i))
root.mainloop()
def collback2(btn,i):
def nothing2():
btn.config(bg='#008000')
bombing(i,btn)
return nothing2
This is the function called bombing. The list used here, bomb, contains values from 0 to 99. Then, if there is a ship in the specified place, the button will be red and a red circle will be drawn on the field with a sound effect. If there is no ship, a black circle will be drawn. And when your turn is over, it will be ai's turn. If either ship is wiped out, the game is over and the winner is the one who wiped out.
battle_ship.py
bomb = [i for i in range(100)]
def bombing(i,btn):
global p1_counter,p2_counter
font = pygame.font.SysFont('comicsens',100)
i -= 1
array = array_2.reshape(-1,1)
width = 65
index=i//10
if i >= 10:
columns = int(str(i)[1:])
else:
columns = i
if array[i] == 1:
pygame.draw.circle(win,(255,0,0),((730+columns*width)+width//2,(55+index*width)+width//2),width//2,0)
bombed_sound.play()
p1_counter += 1
btn.config(bg='#FF0000')
elif array[i] == 0:
pygame.draw.circle(win,(0,0,0),((730+columns*width)+width//2,(55+index*width)+width//2),width//2,0)
failed.play()
if p1_counter == 15:
pygame.mixer.music.stop()
text = font.render('You Win!!',5,(255,0,0))
win.blit(text,(750-text.get_width()/2,200))
pygame.display.update()
victory.play()
num = random.choice(bomb)
bomb.pop(bomb.index(num))
array1 = array_1.reshape(-1,1)
index=num//10
if num >= 10:
columns = int(str(num)[1:])
else:
columns = num
if array1[num] == 1:
pygame.draw.circle(win,(255,0,0),((55+columns*width)+width//2,(55+index*width)+width//2),width//2,0)
p2_counter += 1
bombed_sound.play()
elif array1[num] == 0:
pygame.draw.circle(win,(0,0,0),((55+columns*width)+width//2,(55+index*width)+width//2),width//2,0)
if p2_counter == 15:
pygame.mixer.music.stop()
text = font.render('You Lose...',1,(0,0,255))
win.blit(text,(750-text.get_width()/2,200))
pygame.display.update()
lose.play()
pygame.display.update()
How to make this battleship game is also explained in Youtube, so please have a look if you like it. If you have any questions, please use the comment section of the video or the comment section of this article. Also, if you like it, please subscribe to the channel.
Recommended Posts