Pygame 简单打字游戏

功能描述:

1、点击开始游戏,会出现一段英文文章,并进入60s倒计时

2、如果一分钟内输入完成这段会自动呈现下一段

3、单词正确数实时统计,背景颜色随输入速度而变化

代码:

注意:上面动态图需要放在游戏目录下

import random
import pygame
import sys

class TextData:
    def __init__(self):
        self.all_data = [
            "The author of the game is Jiawang Zhang.",
            "A contented mind is the greatest blessing a man can enjoy in this world.",

            "If you would know the value of money, go and try to borrow some.",

            "If you wish to succeed, you should use persistence as your good friend, experience as your reference, prudence as your brother and hope as your sentry.",

            "Health is certainly more valuable than money, because it is by health that money is procured.",

            "Only those who have the patience to do simple things perfectly ever acquire the skill to do difficult things easily."
        ]        
    def get_single_data(self):
        index = random.randint(0,len(self.all_data)-1)
        return self.all_data[index]
    # def get_data_cut(self, cut_size = 30):
        res = []
        split_data = self.get_single_data().split(' ')
        tem = ""
        for it in split_data:
            if len(tem + it) < cut_size:
                tem += " " + it if tem != "" else it
            else:
                res.append(tem)
                tem = ""
        if tem != "":
            res.append(tem)
        return len(split_data), res, split_data

class TextBox:
    def __init__(self, x, y, w, h, text=""):
        # 文本框起始坐标和宽高
        self.x = x
        self.y = y
        self.width = w
        self.height = h
        self.text = text  # 文本框中文字内容
        self.surface = pygame.Surface((w, h))
        self.surface.fill((255, 255, 255))
    def set_text(self, text_data):
        self.text = text_data
    def add_single_char(self, single_char):
        self.text += single_char
    def del_single_char(self):
        self.text = self.text[:-1]

class TextArea:
    def __init__(self, height, width):
        self.font = pygame.font.Font(None, 32) # 全文需要统一的字体,所以放到这里
        self.boxes = []
        self.TD = TextData()
        self.left_padding = 98
        self.screen_height = height
        self.screen_width = width
        self.text_list = []
        self.split_words = []
        self.input_text = ""
        self.all_words_cnt = 0
        self.acc_words_cnt = 0
        self.pre_input_all_words = 0

        # text_surf = self.font.render(self.text, True, (255, 255, 255))
    def draw_boxes(self, screen):
        i = 0
        _, input_cut, __ = self.cut_data(self.input_text, 40)
        for it in self.boxes:
            if i % 2 == 0:
                text_surf = self.font.render(it.text, True, (109, 158, 235))
            else:
                it.text = input_cut[(i-1) // 2] if ((i-1) // 2) < len(input_cut) else ""
                text_surf = self.font.render(it.text, True, (0, 0, 0))
            i += 1
            screen.blit(it.surface, (it.x, it.y))
            screen.blit(text_surf, (it.x, it.y - 2 + (it.height - text_surf.get_height())),
                        (0, 0, it.width, it.height))
    def add_box(self, x, y, w, h):
        self.boxes.append(TextBox(x, y, w, h))
    def get_text_set_boxes(self):
        self.boxes.clear()
        self.input_text = ""
        self.pre_input_all_words += self.acc_words_cnt
        self.acc_words_cnt = 0
        tem_cnt, self.text_list, self.split_words = self.cut_data(self.TD.get_single_data(), 40)
        self.all_words_cnt += tem_cnt
        top_padding = (self.screen_height // 2) - 45*len(self.text_list) + 10
        if top_padding <= 0:
            print("The article is too long!")
            return
        for it in self.text_list:
            self.boxes.append(TextBox(self.left_padding, top_padding, 600, 30, text=it))
            self.boxes.append(TextBox(self.left_padding, top_padding+40, 600, 30, text=""))
            top_padding += 70+20
    def calc_acc(self):
        cnt = 0
        tem_list = self.input_text.split(' ')
        while(cnt < len(tem_list) and cnt < len(self.split_words)):
            if tem_list[cnt] != self.split_words[cnt]:
                break
            cnt += 1
        self.acc_words_cnt = cnt
    def cut_data(self, data, cut_size = 30):
        res = []
        split_data = data.split(' ')
        tem = ""
        for it in split_data:
            if len(tem + it) < cut_size:
                tem += " " + it if tem != "" else it
            else:
                res.append(tem)
                tem = it
        res.append(tem)
        return len(split_data), res, split_data
    def calc_curr_state(self):
        i = 1
        while i < len(self.boxes):
            tem_compare = self.boxes[i].text, self.boxes[i-1].text
            i += 2
            if tem_compare[0] != tem_compare[1]:
                return True, i - 2
        return False, -1
    def get_score(self):
        return self.acc_words_cnt+self.pre_input_all_words, self.all_words_cnt
    def key_down(self, event):
        unicode_char = event.unicode
        key = event.key
        if key == 8: # 退位键
            self.input_text = self.input_text[0:-1]
            return  
        if key == 301: # 切换大小写键
            return
        if unicode_char != "":
            self.input_text += unicode_char
        else:
            if len(unicode_char) != 0:
                self.input_text += chr(unicode_char)
        if unicode_char == ' ' or unicode_char == '.':
            self.calc_acc()

class ScoreArea:
    def __init__(self):
        self.font = pygame.font.Font(None, 32) # 全文需要统一的字体,所以放到这里
        self.box = None
    def set_box(self, x, y, w, h, text=""):
        self.box = TextBox(x, y, w, h, text)
        # self.box.surface.fill((0,0,0))
    def draw(self, screen, text="(0, 0)", padding=0):
        text = " " + text
        text_surf = self.font.render(text, True, (255, 0, 0))
        screen.blit(self.box.surface, (self.box.x, self.box.y))
        screen.blit(text_surf, (self.box.x+padding, self.box.y - 2 + (self.box.height - text_surf.get_height())),(0, 0, self.box.width, self.box.height))
    def position_in_area(self, x, y):
        return x >= self.box.x and x <= self.box.x+self.box.width and y >= self.box.y and y <= self.box.y+self.box.height

class MoveFun:
    def __init__(self, w, h):
        self.speed = [1, 1]
        self.width = w
        self.height = h
        self.ball = pygame.image.load("gui.gif")
        self.ballrect = self.ball.get_rect()
    def update_position(self):
        self.ballrect = self.ballrect.move(self.speed[0], self.speed[1])
        if self.ballrect.left < 0 or self.ballrect.right > self.width:
            self.speed[0] = - self.speed[0]
        if self.ballrect.top < 0 or self.ballrect.bottom > self.height:
            self.speed[1] = - self.speed[1]
    
class TypingGame:
    def __init__(self, w = 800, h = 650):
        # 设置窗口大小和标题
        self.size = self.width, self.height = w, h
        self.screen = pygame.display.set_mode(self.size)
        pygame.display.set_caption("打字游戏")
        # 设置背景和移动渲染
        self.bg_color = 255, 0, 0
        self.moveball = MoveFun(w, h)
        # 设置文字显示区域
        self.text_area = TextArea(h - 50, w)
        self.text_area.get_text_set_boxes()
        self.score_area = ScoreArea()
        self.score_area.set_box(98, h - 50, 600, 30, "score: ")
        self.finish_area = ScoreArea()
        self.finish_area.set_box(98, h // 2, 600, 30, "game over")
        self.score = (0, 0)
        self.start_time = None
    def calc_speed(self):
        curr_length = len(self.text_area.input_text) + self.text_area.pre_input_all_words
        time_dis = (pygame.time.get_ticks() - self.start_time + 1.0) / 6000.0
        speed = min((curr_length / time_dis) / 50.0, 1.0)
        return (255 - int(speed*255), int(speed*255), 0)
    def Start(self):
        self.start_time = pygame.time.get_ticks()
    def update_backgroud(self):
        self.moveball.update_position()
        if self.start_time != None:
            self.bg_color = self.calc_speed()
        self.screen.fill(self.bg_color)    # 背景
        self.screen.blit(self.moveball.ball, self.moveball.ballrect) # 碰撞移动
    def update_game(self):
        # 游戏开始后渲染
        if self.start_time == None:
            self.score_area.draw(self.screen, "Click to start the game ", padding=170) # 分数面板
        else:
            now_time = pygame.time.get_ticks()
            if (now_time - self.start_time) < 60000.0:
                self.text_area.draw_boxes(self.screen) # 文本框
                self.score = self.text_area.get_score()
                self.score_area.draw(self.screen, "score: " + str(self.score) + "    time: " + str(60 - int((now_time - self.start_time) / 1000)) + " s", padding=180) # 分数面板
                if self.score[0] == self.score[1] and self.score[0] != 0:
                    self.text_area.get_text_set_boxes()
            else:
                self.score_area.draw(self.screen, "score: " + str(self.score) + "    time: " + "0.00", padding=180) # 分数面板
                self.finish_area.draw(self.screen, "game over", padding=240) # 结束面板
     


if __name__ == '__main__':

    pygame.init()
    Tgame = TypingGame()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if Tgame.start_time != None:
                    Tgame.text_area.key_down(event)
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if Tgame.start_time == None:
                    x, y = pygame.mouse.get_pos()
                    if Tgame.score_area.position_in_area(x, y):
                        Tgame.Start()
                    
        ################ 背景+碰撞移动更新 ################
        Tgame.update_backgroud()
        Tgame.update_game()
        
        ################ 更新画面 ################
        pygame.display.update()
        pygame.time.delay(50)

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值