用pygame做一个背单词小游戏~

最终功能:显示问题和选项在页面上,根据玩家的选择作出回应,正确的选项变绿,错误的选项变红,并记录玩家的得分
先上效果图~
(1)回答正确的页面,右上角可以积分
在这里插入图片描述
(2)回答错误的页面
在这里插入图片描述
为了实现上述功能,需要考虑以下几个点:

  1. 用什么样的方式将题目和选项显示在屏幕上
  2. 如何根据玩家的回答变选项的颜色

首先,关于第一点的思路如下
因为题目和选项的内容在不断变化,给每一个问题和选项都设置一个输出语句不现实
在这种情况下,用文件就比较合适
用readlines方法读出来的文件会存到一个列表中,文件中的每一行都是列表中的一项,但是用print语句输出这个列表后发现,列表中的每一项后面都会带一个换行符
为了删除这个换行符,使用了如下方法
此处还要注意,因为文件中有中文,所以打开文件时必须加上编码方式(应该就是这个原因,我加了才对了)

   f=open(textname,encoding='utf-8')  #transfer gbk(the way of chinese text) to utf-8
        question_data=f.readlines()
        f.close()
        for question_line in question_data:
            self.data.append(question_line.strip()) #load in data[] in lines without any strip
            self.total+=1

也就是逐行读入,再逐项删除换行字符
将数据存入文件还需要一定的格式:
第一行是问题,第2-5行是选项,第6行是答案
就像这样:

接近,方法,通路
access
acess
acces
eccess
1

好了,题库的问题解决了,接下来我们考虑显示的问题
将文字显示在窗口有3步:
(1)new一个Font对象(java的术语习惯了哈哈)
(2)将字体转换为位图
(3)贴图
这里需要特别注意的是,Font没有中文,我用了这个方法显示中文:
自己下载一个中文字体的包,与py文件保存在一起,把Font构造方法中的None改成字体文件的文件名
另外,整个窗口有多处需要显示文字,为了方便,直接把上述操作打包成一个函数,代码如下:

def print_text(font,x,y,text,color=(255,255,255),shadow=True):
    #font conversion
    if shadow:
        #create 2D font
        img_text=font.render(text,True,(0,0,0))
        screen.blit(img_text,(x-2,y-2))

    img_text=font.render(text,True,color)
    screen.blit(img_text,(x,y))

这里设置了shadow参数,决定是否显示2D字体(就是普通字体后面带一块阴影哈哈)

接下来,我们来解决如何根据用户的输入来改变选项颜色的问题:
逻辑很简单:接收用户输入->判断是否正确->改变相应选项的颜色
接收用户输入+判断正误:

 #handdle player's answer
    def handdle_answer(self,player_input):
        if not self.scored and not self.failed:
            #in case to when the player have answered question without pressing enter to next
            if player_input==self.correct:
                self.scored=True
                self.score+=1
            else:
                self.wronganswer=player_input
                self.failed=True

每一题的正确答案都保存在“第六行”(题库文件把答案序号放在了每一题的最后),用correct来保存
与用户输入作对比,正确就置scored属性(下面会讲为啥定义这个变量)为True,反之把用户输入保存在wronganswer变量中,因为错误的选项需要变成红色,并置failed属性(下面会讲)为True
在近期的学习中,我觉得在某些情况下很有必要定义“flag”类型变量,就是标记,它只有两个值,可以放在if语句中做相应操作
这个某些情况,我觉得就是当你的程序需要根据某些结果做出某些反应
这里的scored和failed就是
用户输入正确时,需要将正确选项变成绿色,输入错误时,需要将用户的选择变红,正确的选项变绿

变换颜色:
我觉得这个程序的神奇之处之一就是变颜色这个操作
我们知道,颜色就在将文本贴在窗口上的函数中的一个参数
四个选项的颜色参数每一题都在变化
我们现在能利用的就是已经知道了用户的选择的选项和正确选项,而且它们都是1,2,3,4这种类型
此时就应该想到列表的下标
我们设置一个放四个选项颜色的列表,通过判断用户输入的结果来改变列表的对应项
最后直接取出列表中的对应项来做文本的颜色参数就ok

 #handdle player's answer
          #respond to correct answer
        if self.scored:
            self.colors=[white,white,white,white]  #Is this line  restless?
            self.colors[self.correct-1]=green
            print_text(font1,210,380,"CORRECT!",green)
            print_text(font2,130,420,"Press Enter For Next Question",green)
        elif self.failed:
            self.colors=[white,white,white,white]
            self.colors[self.correct-1]=green
            self.colors[self.wronganswer-1]=red
            print_text(font1,220,380,"INCORRECT!",red)
            print_text(font2,170,420,"Press Enter For Next Question",green) #former is x,latter is y

        #display answers
        print_text(font1,5,170,"ANSWERS")
        print_text(font2,20,210,"1-"+self.data[self.current+1],self.colors[0])
        print_text(font2,20,240,"2-"+self.data[self.current+2],self.colors[1])
        print_text(font2,20,270,"3-"+self.data[self.current+3],self.colors[2])
        print_text(font2,20,300,"4-"+self.data[self.current+4],self.colors[3])

好了,我觉得这个程序的精华大概就是这些
哦对,游戏的主逻辑都放在了类里,前面说的什么failed,scored 都是类的属性
其实我本来还想说一下游戏的循环,但是我一直没有把while循环理解透,下次再来吧~
另外还需说明的是,这个程序并不完全是我想出来的,我参照了Jonathan S.Harbour编写的Trivia游戏

接下来是源代码,字体文件和题库大家可以自行下载和编写,题库用记事本写就OK

import pygame
import sys
from pygame.locals import *
import time

#main logic
class Recite():
    def __init__(self,textname):
        self.data=[] #file list
        self.current=0 #data current index
        self.correct=0 #true answer
        self.score=0 #player's socre
        self.scored=False #flag
        self.failed=False #flag
        self.wronganswer=0 #player's wronganswer
        self.total=0 #total of the file's lines
        self.colors=[white,white,white,white] #options'color
        self.question_number=1 #record question number
        #load file to data list
        f=open(textname,encoding='utf-8')  #transfer gbk(the way of chinese text) to utf-8
        question_data=f.readlines()
        f.close()
        for question_line in question_data:
            self.data.append(question_line.strip()) #load in data[] in lines without any strip
            self.total+=1

    #show_question
    def show_question(self):
        print_text(font1,160,5,"CET4 WORDS TEST")
        print_text(font2,150,500-30,"Press keys (1-4) To Answer",purple)
        print_text(font2,530,5,"SCORE",purple)
        print_text(font2,550,25,str(self.score),purple)

        #get correct answer from data[]
        self.correct=int(self.data[self.current+5]) #the lines are string

        #display question
        print_text(font1,5,80,"QUESTION "+str(self.question_number))
        print_text(font2,20,120,self.data[self.current],yellow)

        #respond to correct answer
        if self.scored:
            self.colors=[white,white,white,white]  #Is this line  restless? Yes
            self.colors[self.correct-1]=green
            print_text(font1,210,380,"CORRECT!",green)
            print_text(font2,130,420,"Press Enter For Next Question",green)
        elif self.failed:
            self.colors=[white,white,white,white]
            self.colors[self.correct-1]=green
            self.colors[self.wronganswer-1]=red
            print_text(font1,220,380,"INCORRECT!",red)
            print_text(font2,170,420,"Press Enter For Next Question",green) #former is x,latter is y

        #display answers
        print_text(font1,5,170,"ANSWERS")
        print_text(font2,20,210,"1-"+self.data[self.current+1],self.colors[0])
        print_text(font2,20,240,"2-"+self.data[self.current+2],self.colors[1])
        print_text(font2,20,270,"3-"+self.data[self.current+3],self.colors[2])
        print_text(font2,20,300,"4-"+self.data[self.current+4],self.colors[3])



    #next_question
    def next_question(self):
        self.scored=False
        self.failed=False
        self.current+=6
        self.colors=[white,white,white,white]
        self.correct=0   #reset  arributes
        if self.current>self.total:
            self.current=0
        self.question_number+=1

    #handdle player's answer
    def handdle_answer(self,player_input):
        if not self.scored and not self.failed:
            #in case to when the player have answered question without pressing enter to next
            if player_input==self.correct:
                self.scored=True
                self.score+=1
            else:
                self.wronganswer=player_input
                self.failed=True


def print_text(font,x,y,text,color=(255,255,255),shadow=True):
    #font conversion
    if shadow:
        #create 2D font
        img_text=font.render(text,True,(0,0,0))
        screen.blit(img_text,(x-2,y-2))

    img_text=font.render(text,True,color)
    screen.blit(img_text,(x,y))

#program initialized
#create pygame windows,and make preparations to the game
pygame.init()
screen=pygame.display.set_mode((600,500))
pygame.display.set_caption("Cet-4 words dictation")
font1=pygame.font.Font('mnjyx.ttf',40)  #Chinese font or it can't be identified
font2=pygame.font.Font('mnjyx.ttf',24)
white=255,255,255
purple=255,0,255
yellow=255,255,0
green=0,255,0
red=255,0,0


#new a object
recite=Recite("CET4 words.txt")

#game loop
while True:
    for event in pygame.event.get():
        if event.type== QUIT:
            sys.exit()
        elif event.type==KEYUP:
            if event.key==pygame.K_ESCAPE:
                sys.exit()
            elif event.key==pygame.K_1:
                recite.handdle_answer(1)
            elif event.key==pygame.K_2:
                recite.handdle_answer(2)
            elif event.key==pygame.K_3:
                recite.handdle_answer(3)
            elif event.key==pygame.K_4:
                recite.handdle_answer(4)
            elif event.key==pygame.K_RETURN:
                recite.next_question()
        #clear screen
        screen.fill((0,0,200))

        #show_question
        recite.show_question()

        time.sleep(0.0005)

        #update
        pygame.display.update()

如果我的代码还有可以优化改进的部分,欢迎各路大神指出

自认为今后功能优化可以有:
1.题库存放到数据库里,通过数据库来调
2.将玩家答错的题提取出来,定期发送到他的微信上,提醒他背诵
(因为前两天看到一个文章说可以用python写一个微信提醒备忘录,觉得hen6)
3. 联机玩儿法,在规定的时间,看谁答对的最多,并设置排行榜

发布了6 篇原创文章 · 获赞 10 · 访问量 976

猜你喜欢

转载自blog.csdn.net/qq_41625102/article/details/88831182