概要
この記事内では,pythonのpygameライブラリを用いて計算問題のアプリケーション(アプリ)の作成方法を紹介します.アプリ内では以下の2個の特徴を含みますので,似たような機能を作成したい方はぜひご参照ください.
- 2桁×1桁の計算の自動生成
- プロセスサークル(プロセスバーの円形のもの)の作り方
動作の様子は以下です.
右上のプロセスバーは7sで一周します.また正解と不正解によって正解数と不正解数が増えます.
作成したプログラム
はじめにコード全体を載せます.
import pygame
import random
import time
import numpy as np
import sys
PI = np.pi
class CalculationApp:
def __init__(self):
#initialization
pygame.init()
#screen
self.screen_width = 400
self.screen_height = 250
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
pygame.display.set_caption("Calculation App")
#font
self.font = pygame.font.Font(None, 50)
self.font_text = pygame.font.Font(None,35)
self.font_answer = pygame.font.Font(None,22)
# create questions
self.num1 = random.randint(10, 99)
self.num2 = random.randint(1, 9)
self.answer = ""
#limit
self.time_limit = 10
self.remaining_time = self.time_limit
# arc param
self.center = (350, 45)
self.aRadius = 20
self.start_angle = -2*PI/2
self.end_angle = PI/2
self.arc_color = (0,255, 0)
self.width = 15
# answer
self.correct_num = 0
self.incorrect_num = 0
self.num = 0
# time
self.start_time = time.time()
self.end_time = time.time()
self.elapsed_time = self.end_time-self.start_time
def update(self):
# fill white
self.screen.fill((255, 255, 255))
# question
question_text = self.font.render(f"{self.num1} × {self.num2} =", True, (0, 0, 0))
self.screen.blit(question_text, (70, 130))
# answer
answer_text = self.font.render(self.answer, True, (0, 0, 0))
self.screen.blit(answer_text, (210, 130))
# text
issue_text = self.font_text.render("Calculate 100 questions!!",True,(0,0,0))
self.screen.blit(issue_text,(10,40))
remain_text = self.font_answer.render(f"{self.num}/ 100",True,(0,0,0))
self.screen.blit(remain_text,(340,230))
# correct and incorrect
correct = self.font_answer.render(f"Correct Answers:{self.correct_num} Incorrect Answers:{self.incorrect_num}",True,(0,0,0))
self.screen.blit(correct,(10,230))
# process circle
self.start_angle,self.end_angle = self.updateprocesscircle()
pygame.draw.arc(
self.screen, self.arc_color,
(self.center[0] - self.aRadius, self.center[1] - self.aRadius, self.aRadius * 2, self.aRadius * 2),
self.start_angle,
self.end_angle,
width = self.width)
# draw
pygame.display.flip()
def updateprocesscircle(self):
self.end_time = time.time()
self.elapsed_time = self.end_time-self.start_time
# 7 seconds
if(self.elapsed_time>7.0):
self.start_time = time.time()
self.end_time = time.time()
rate = PI/2
self.timeup()
else:
rate = PI/2-(self.elapsed_time/7.0)*2*PI
return rate,PI/2
def timeclear(self):
self.start_time = time.time()
self.end_time = time.time()
def timeup(self):
self.num1 = random.randint(10, 99)
self.num2 = random.randint(1, 9)
self.incorrect_num += 1
self.num += 1
self.answer = ""
def run(self):
# ゲームループ
running = True
while(running):
for event in pygame.event.get():
if(event.type == pygame.QUIT):
running = False
if(event.type == pygame.KEYDOWN):
if(event.key == pygame.K_ESCAPE):
running = False
elif(event.key == pygame.K_RETURN):
try:
user_answer = int(self.answer)
correct_answer = self.num1 * self.num2
# correct
if(user_answer == correct_answer and self.num<100):
self.num1 = random.randint(10, 99)
self.num2 = random.randint(1, 9)
self.correct_num += 1
self.num += 1
self.answer = ""
self.timeclear()
# incorrect
elif(user_answer != correct_answer and self.num<100):
self.incorrect_num += 1
self.num += 1
self.num1 = random.randint(10, 99)
self.num2 = random.randint(1, 9)
self.answer = ""
self.timeclear()
else:
running = False
except ValueError:
# when the input is wrong
self.answer = ""
elif(event.key in (pygame.K_0, pygame.K_1, pygame.K_2, pygame.K_3, pygame.K_4, pygame.K_5, pygame.K_6, pygame.K_7, pygame.K_8, pygame.K_9)):
# add
self.answer += event.unicode
elif(event.key == pygame.K_BACKSPACE):
self.answer = ""
self.update()
# when runnning is false
pygame.quit()
sys.exit()
if __name__ == "__main__":
app = CalculationApp()
app.run()
以上が全体のコードです.以下では計算方法の追加部分と視覚的な残り時間の提示方法を書きます.
2桁×1桁の計算の自動生成
コードの主な該当部分はrun()とupdate()です.
###########
try:
user_answer = int(self.answer)
correct_answer = self.num1 * self.num2
###########
ここでは正答のチェックを行っています.
def update(self):
######################
# question
question_text = self.font.render(f"{self.num1} × {self.num2} =", True, (0, 0, 0))
self.screen.blit(question_text, (70, 130))
######################
update内ではtextの描画を担当しています.question_textを変更することで任意の問題に変更できます.
視覚的な残り時間の提示(プロセスサークル)
pygameのpygame.draw.arc()がややプロセスサークルを作成するのに不便だったので注意です.
draw.arcのパラメータはpygame.draw.arc(スクリーン, 色, 描画する領域(四角形), start angle, end angle)が必須になるのですが,angleに基本的に正の値を与えると,例えば start angle = 0, end angle = PIとしてend angleを増加させると反時計回りになってしまいます.
そこでプログラムではend angleを残り時間によって減少させています.
def updateprocesscircle(self):
self.end_time = time.time()
self.elapsed_time = self.end_time-self.start_time
# 7 seconds
if(self.elapsed_time>7.0):
self.start_time = time.time()
self.end_time = time.time()
rate = PI/2
self.timeup()
else:
rate = PI/2-(self.elapsed_time/7.0)*2*PI
return rate,PI/2
なぜ作ったか?(追記)
作成した背景としては,ストレスがかかりそうなタスクを行う必要があり,かつプロセスバーみたいなものを作成したかったからです.