函数式编程中的 Python 弹跳球游戏

发布于 2025-01-13 17:45:38 字数 7694 浏览 3 评论 0原文

这是一款常见的街机游戏,目标是尽可能多地击中所有目标以获得最高分。每次球击中“石头”,您将获得 1 分,如果击中 2 个“石头”,您将获得 2 分。如果玩家未能接住横杆或“杆”上的球,则游戏结束。

我的任务就是把这个用面向对象编程编写的游戏变成函数式编程。

import time

class Ball:
    def __init__(self, cvs, pole, stones, scre):
        self.stones = stones
        self.cvs = cvs
        self.pole = pole
        self.scre = scre
        self.bottom_hit = False
        self.hit = 0
        self.id = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
        self.cvs.move(self.id, 230, 461)

        self.a = 3
        self.b = -3
        self.cvs.move(self.id, self.a, self.b)
        self.cvs_height = canvas.winfo_height()
        self.cvs_width = canvas.winfo_width()

    def stone_strike(self, push):
        for stone_line in self.stones:
            for stone in stone_line:
                stone_push = self.cvs.coords(stone.id)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            self.hit += 1
                            self.scre.configure(text="Score: " + str(self.hit))
                            self.cvs.delete(stone.id)
                            return True
                except:
                    continue
        return False

    def pole_strike(self, push):
        pole_push = self.cvs.coords(self.pole.id)
        if push[2] >= pole_push[0] and push[0] <= pole_push[2]:
            if push[3] >= pole_push[1] and push[1] <= pole_push[3]:
                return True
            return False

    def draw(self):
        self.cvs.move(self.id, self.a, self.b)
        push = self.cvs.coords(self.id)
        if self.stone_strike(push):
            self.b = 3
        if push[1] <= 0:
            self.b = 3
        if push[3] >= self.cvs_height:
            self.bottom_hit = True
        if push[0] <= 0:
            self.a = 3
        if push[2] >= self.cvs_width:
            self.a = -3
        if self.pole_strike(push):
            self.b = -3


class Pole:
    def __init__(self, cvs):
        self.cvs = cvs
        self.id = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
        self.cvs.move(self.id, 200, 485)
        self.a = 0
        self.cvs_width = canvas.winfo_width()
        self.cvs.bind_all("<Left>", self.turn_left)
        self.cvs.bind_all("<Right>", self.turn_right)

    def draw(self):
        push = self.cvs.coords(self.id)
        if push[0] + self.a <= 0:
            self.a = 0
        if push[2] + self.a >= self.cvs_width:
            self.a = 0
        self.cvs.move(self.id, self.a, 0)

    def turn_left(self, event):
        self.a = -5

    def turn_right(self, event):
        self.a = 5


class Stone:
    def __init__(self):
        self.id = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")


def start_game(event):
    score.configure(text="Score: 00")
    canvas.delete("all")
    pole = Pole(canvas)
    stones = []
    for i in range(0, 5):
        b = []
        for j in range(0, 19):
            tmp = Stone()
            b.append(tmp)
        stones.append(b)

    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j].id, 25 * j, 25 * i)

    ball = Ball(canvas, pole, stones, score)
    root.update()

    time.sleep(1)
    while 1:
        if not ball.bottom_hit:
            ball.draw()
            pole.draw()
            root.update()
            time.sleep(0.01)
            if ball.hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break

root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", start_game)
root.mainloop()

这是我写的代码。肯定存在逻辑错误,因为它不起作用。有什么想法吗?

import time

def startgame(event):
    score.configure(text="score:00")
    canvas.delete("all")
    canvas_width = canvas.winfo_width()
    canvas_height = canvas.winfo_height()
    pole = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
    canvas.move(pole, 200, 425)
    pa = 0
    
    def turn_left(event):
        pa = -5

    def turn_right(event):
        pa = 5

    def stone_strike(push):
        for stone_line in stones:
            for stone in stone_line:
                stone_push = canvas.coords(stone)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            hit += 1
                            score.configure(text="score:" + str(hit))
                            stonaki.delete()
                            return True
                except:
                    continue
        return False

    def pole_strike(push_b):
        pole_push = canvas.coords(pole)
        if push_b[2] >= pole_push[0] and push_b[0] <= pole_push[2]:
            if push_b[3] >= pole_push[1] and push_b[1] <= pole_push[3]:
                return True
            return False



    canvas.bind_all("<Left>", turn_left)
    canvas.bind_all("<Right>", turn_right)
    push_p = canvas.coords(pole)
    if push_p[0] + pa <= 0:
        pa = 0
    if push_p[2] + pa >= canvas_width:
        pa = 0


    stones = []
    for i in range(0, 5):
        lista = []
        for j in range(0, 19):
            stonaki = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")
            lista.append(stonaki)
        stones.append(lista)
    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j], 25 * j, 25 * i)

    root.update()
    
    bottom_hit = False
    hit = 0
    ball = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
    canvas.move(ball, 230, 461)
    ba = 3
    bb = -3
    canvas.move(ball, ba, bb)
    push_b = canvas.coords(ball)

    if stone_strike(push_b):
        bb = 3
    if push_b[1] <= 0:
        bb = 3
    if push_b[3] >= canvas_height:
        bottom_hit = True
    if push_b[0] <= 0:
        ba = 3
    if push_b[2] >= canvas_width:
        ba = -3
    if pole_strike(push_b):
        bb = -3
    
    time.sleep(1)
    while 1:
        if not bottom_hit:
            root.update()
            time.sleep(0.01)
            if hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break


root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", startgame)
root.mainloop()

This is a common arcade game, the goal is to hit all targets as many times as you can to earn the highest score. Every time the ball hits a "stone" you earn 1 point, and if it hits 2 you earn 2 points, respectively. If the player fails to catch the ball on the bar or "pole" then the game is over.

My assignment is to turn this game written in object-oriented programming into functional programming.

import time

class Ball:
    def __init__(self, cvs, pole, stones, scre):
        self.stones = stones
        self.cvs = cvs
        self.pole = pole
        self.scre = scre
        self.bottom_hit = False
        self.hit = 0
        self.id = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
        self.cvs.move(self.id, 230, 461)

        self.a = 3
        self.b = -3
        self.cvs.move(self.id, self.a, self.b)
        self.cvs_height = canvas.winfo_height()
        self.cvs_width = canvas.winfo_width()

    def stone_strike(self, push):
        for stone_line in self.stones:
            for stone in stone_line:
                stone_push = self.cvs.coords(stone.id)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            self.hit += 1
                            self.scre.configure(text="Score: " + str(self.hit))
                            self.cvs.delete(stone.id)
                            return True
                except:
                    continue
        return False

    def pole_strike(self, push):
        pole_push = self.cvs.coords(self.pole.id)
        if push[2] >= pole_push[0] and push[0] <= pole_push[2]:
            if push[3] >= pole_push[1] and push[1] <= pole_push[3]:
                return True
            return False

    def draw(self):
        self.cvs.move(self.id, self.a, self.b)
        push = self.cvs.coords(self.id)
        if self.stone_strike(push):
            self.b = 3
        if push[1] <= 0:
            self.b = 3
        if push[3] >= self.cvs_height:
            self.bottom_hit = True
        if push[0] <= 0:
            self.a = 3
        if push[2] >= self.cvs_width:
            self.a = -3
        if self.pole_strike(push):
            self.b = -3


class Pole:
    def __init__(self, cvs):
        self.cvs = cvs
        self.id = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
        self.cvs.move(self.id, 200, 485)
        self.a = 0
        self.cvs_width = canvas.winfo_width()
        self.cvs.bind_all("<Left>", self.turn_left)
        self.cvs.bind_all("<Right>", self.turn_right)

    def draw(self):
        push = self.cvs.coords(self.id)
        if push[0] + self.a <= 0:
            self.a = 0
        if push[2] + self.a >= self.cvs_width:
            self.a = 0
        self.cvs.move(self.id, self.a, 0)

    def turn_left(self, event):
        self.a = -5

    def turn_right(self, event):
        self.a = 5


class Stone:
    def __init__(self):
        self.id = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")


def start_game(event):
    score.configure(text="Score: 00")
    canvas.delete("all")
    pole = Pole(canvas)
    stones = []
    for i in range(0, 5):
        b = []
        for j in range(0, 19):
            tmp = Stone()
            b.append(tmp)
        stones.append(b)

    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j].id, 25 * j, 25 * i)

    ball = Ball(canvas, pole, stones, score)
    root.update()

    time.sleep(1)
    while 1:
        if not ball.bottom_hit:
            ball.draw()
            pole.draw()
            root.update()
            time.sleep(0.01)
            if ball.hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break

root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", start_game)
root.mainloop()

Here is the code I have written.. There must be logical errors since it's not working. Any ideas??

import time

def startgame(event):
    score.configure(text="score:00")
    canvas.delete("all")
    canvas_width = canvas.winfo_width()
    canvas_height = canvas.winfo_height()
    pole = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
    canvas.move(pole, 200, 425)
    pa = 0
    
    def turn_left(event):
        pa = -5

    def turn_right(event):
        pa = 5

    def stone_strike(push):
        for stone_line in stones:
            for stone in stone_line:
                stone_push = canvas.coords(stone)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            hit += 1
                            score.configure(text="score:" + str(hit))
                            stonaki.delete()
                            return True
                except:
                    continue
        return False

    def pole_strike(push_b):
        pole_push = canvas.coords(pole)
        if push_b[2] >= pole_push[0] and push_b[0] <= pole_push[2]:
            if push_b[3] >= pole_push[1] and push_b[1] <= pole_push[3]:
                return True
            return False



    canvas.bind_all("<Left>", turn_left)
    canvas.bind_all("<Right>", turn_right)
    push_p = canvas.coords(pole)
    if push_p[0] + pa <= 0:
        pa = 0
    if push_p[2] + pa >= canvas_width:
        pa = 0


    stones = []
    for i in range(0, 5):
        lista = []
        for j in range(0, 19):
            stonaki = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")
            lista.append(stonaki)
        stones.append(lista)
    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j], 25 * j, 25 * i)

    root.update()
    
    bottom_hit = False
    hit = 0
    ball = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
    canvas.move(ball, 230, 461)
    ba = 3
    bb = -3
    canvas.move(ball, ba, bb)
    push_b = canvas.coords(ball)

    if stone_strike(push_b):
        bb = 3
    if push_b[1] <= 0:
        bb = 3
    if push_b[3] >= canvas_height:
        bottom_hit = True
    if push_b[0] <= 0:
        ba = 3
    if push_b[2] >= canvas_width:
        ba = -3
    if pole_strike(push_b):
        bb = -3
    
    time.sleep(1)
    while 1:
        if not bottom_hit:
            root.update()
            time.sleep(0.01)
            if hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break


root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", startgame)
root.mainloop()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

玩世 2025-01-20 17:45:38

在将这个用面向对象编程编写的游戏转变为函数式编程的过程中,我们需要照顾每个函数正在使用的变量/小部件。如果我们要对本地函数中的某些变量进行更改,并希望保留函数调用结束后所做的更改,那么我将将这些变量/小部件设为全局

此外,在 OOP 代码中,每次使用函数 draw() 在画布中对“球”和“杆”进行更改。因此,为相同的 drawB()drawP() 创建两个函数:

from tkinter import *
import time

def startgame(event):
    score.configure(text="score:00")
    canvas.delete("all")
    canvas_width = canvas.winfo_width()
    canvas_height = canvas.winfo_height()
    global pole,pa, ba,bb,bottom_hit, hit,ball
    pole = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
    canvas.move(pole, 200, 425)
    pa = 0
    
    def turn_left(event):
        global pa
        pa = -5

    def turn_right(event):
        global pa
        pa = 5

    def stone_strike(push):
        global stones, hit
        for stone_line in stones:
            for stone in stone_line:
                stone_push = canvas.coords(stone)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            hit += 1
                            score.configure(text="score:" + str(hit))
                            canvas.delete(stone)   #what to delete
                            return True
                except:
                    continue
        return False

    def pole_strike(push_b):
        global pole
        pole_push = canvas.coords(pole)
        if push_b[2] >= pole_push[0] and push_b[0] <= pole_push[2]:
            if push_b[3] >= pole_push[1] and push_b[1] <= pole_push[3]:
                return True
            return False



    canvas.bind_all("<Left>", turn_left) 
    canvas.bind_all("<Right>", turn_right)

    def drawP():
        global pa,pole
        push_p = canvas.coords(pole)
        if push_p[0] + pa <= 0:
            pa = 0
        if push_p[2] + pa >= canvas_width:
            pa = 0
        canvas.move(pole, pa, 0)

    global stones
    stones = []
    for i in range(0, 5):
        lista = []
        for j in range(0, 19):
            stonaki = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")
            lista.append(stonaki)
        stones.append(lista)
    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j], 25 * j, 25 * i)

    
    bottom_hit = False
    hit = 0
    ball = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
    canvas.move(ball, 230, 461)
    
    ba = 3
    bb = -3

    root.update()
    
    def drawB():
        global ba,bb,bottom_hit, hit,ball,pole
        canvas.move(ball, ba, bb)
        push_b = canvas.coords(ball)

        if stone_strike(push_b):
            bb = 3
        if push_b[1] <= 0:
            bb = 3
        if push_b[3] >= canvas_height:
            bottom_hit = True
        if push_b[0] <= 0:
            ba = 3
        if push_b[2] >= canvas_width:
            ba = -3
        if pole_strike(push_b):
            bb = -3
    
    time.sleep(1)
    while 1:
        if not bottom_hit:
            drawB()
            drawP()
            root.update()
            time.sleep(0.01)
            if hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break


root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", startgame)
root.mainloop()

您可以进一步优化此代码。

In the process of turning this game written in object-oriented programming into functional programming, we need to take care of variables/widgets which are being used by every function. If we are making changes to some variable in a local function and want to retain the changes made after the function call ends, so I will be making those variables/widgets global.

Also, in the OOP code, changes are being made every time in the canvas using functions draw() for both "ball" and "pole". Hence making two functions for the same drawB() and drawP():

from tkinter import *
import time

def startgame(event):
    score.configure(text="score:00")
    canvas.delete("all")
    canvas_width = canvas.winfo_width()
    canvas_height = canvas.winfo_height()
    global pole,pa, ba,bb,bottom_hit, hit,ball
    pole = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
    canvas.move(pole, 200, 425)
    pa = 0
    
    def turn_left(event):
        global pa
        pa = -5

    def turn_right(event):
        global pa
        pa = 5

    def stone_strike(push):
        global stones, hit
        for stone_line in stones:
            for stone in stone_line:
                stone_push = canvas.coords(stone)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            hit += 1
                            score.configure(text="score:" + str(hit))
                            canvas.delete(stone)   #what to delete
                            return True
                except:
                    continue
        return False

    def pole_strike(push_b):
        global pole
        pole_push = canvas.coords(pole)
        if push_b[2] >= pole_push[0] and push_b[0] <= pole_push[2]:
            if push_b[3] >= pole_push[1] and push_b[1] <= pole_push[3]:
                return True
            return False



    canvas.bind_all("<Left>", turn_left) 
    canvas.bind_all("<Right>", turn_right)

    def drawP():
        global pa,pole
        push_p = canvas.coords(pole)
        if push_p[0] + pa <= 0:
            pa = 0
        if push_p[2] + pa >= canvas_width:
            pa = 0
        canvas.move(pole, pa, 0)

    global stones
    stones = []
    for i in range(0, 5):
        lista = []
        for j in range(0, 19):
            stonaki = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")
            lista.append(stonaki)
        stones.append(lista)
    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j], 25 * j, 25 * i)

    
    bottom_hit = False
    hit = 0
    ball = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
    canvas.move(ball, 230, 461)
    
    ba = 3
    bb = -3

    root.update()
    
    def drawB():
        global ba,bb,bottom_hit, hit,ball,pole
        canvas.move(ball, ba, bb)
        push_b = canvas.coords(ball)

        if stone_strike(push_b):
            bb = 3
        if push_b[1] <= 0:
            bb = 3
        if push_b[3] >= canvas_height:
            bottom_hit = True
        if push_b[0] <= 0:
            ba = 3
        if push_b[2] >= canvas_width:
            ba = -3
        if pole_strike(push_b):
            bb = -3
    
    time.sleep(1)
    while 1:
        if not bottom_hit:
            drawB()
            drawP()
            root.update()
            time.sleep(0.01)
            if hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break


root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", startgame)
root.mainloop()

You may further optimize this code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文