当前位置: 首页 > 面试题库 >

您如何分别控制两个不同的对象(两个玩家的乒乓球游戏)?

张智
2023-03-14
问题内容

因此,我发现了这个名叫法拉利(Ferrari)的家伙创造的这款出色的乒乓球游戏,我的任务是使他成为两名拥有2分但没有高分的玩家。我做了很多尝试,除了当我制作第二组控制运动的代码时,它要么被完全忽略,要么按分配给它的向上按钮,它将一直向上移动,而不会向下移动。

from decimal import Decimal, getcontext
getcontext().prec = 20
import time,random,os,sys
from Tkinter import *
from tkFileDialog import *
import tkFont
import os,sys

## decimal is for numbers and arithmatic that use irrational numbers
## Tkinter is the graphical interface for the program
## tkFont is the window that pops up
## os is operating system
## sys is system


## there are 2 different variables for player 1 and player 2 because one variable is a variable for a number, the other creates the rectangle(the actual paddle)
## these are just variables that represent numbers

refreshrate=100
do = 1
done=0
ballX=320
ballY=240
playerone=180
py2=180
pause=0
up=0
down=0
root = Tk()
root.title("Pong")
c = Canvas(root,width=640,height=480,bg='black')
c.pack()
xc = float(2)
yc = float(random.randint(-3,3))
while(yc==0):
    yc = float(random.randint(-3,3))
ball = c.create_oval(ballX-10,ballY-10,ballX+10,ballY+10,fill='white')
player = c.create_rectangle(610,playerone,625,playerone+120,fill='blue')
playertwo = c.create_rectangle(15,playerone,30,playerone+120,fill='blue')
c.create_rectangle(318,0,322,480,fill='white')
c.create_rectangle(318,0,322,30,fill='white')
score = 0
escore= 0
lives = 5
font = tkFont.Font(family = "Book Antiqua", size = 15, weight = "bold")

## to change the keys in which you press to control the paddles, change the letter or arrow key between the quotation marks next to str a   
## player1 controls

def up(event):
    global playerone, player, py2, playertwo, high, low
    up = 1
def down(event):
    global playerone, player, py2, playertwo, high, low
    down = 1
def escape(event):
    global do, lives
    lives = -1
    do = 0
    root.quit
    root.quit()
def onkeyrelease(event):
    global up, down, do, lives, pause
    key = event.keysym
    if (str(key)=="w"):
        up = 0
    if (str(key)=="s"):
        down = 0
    if (str(key)=="Escape" and done==1):
        root.quit
        do = 0
        lives = -1
        root.quit()
    if (str(key)=="p"):
        if(pause==1):
            pause=0
        elif(pause==0):
            pause=1
def buttoninit():
    root.bind("<w>",up)
    root.bind("<s>",down)
    root.bind("`",escape)
    root.bind('<KeyRelease>', onkeyrelease)
buttoninit()

## player2 controls

def high(event):
    global playerone, player, py2, playertwo, up, down
    up = 1
def low(event):
    global playerone, player, py2, playertwo, up, down
    down = 1
def leave(event):
    global do, lives
    lives = -1
    do = 0
    root.quit
    root.quit()
def offkeyrelease(event):
    global up, down, do, lives, pause
    key = event.keysym
    if (str(key)=="Up"):
        up = 0
    if (str(key)=="Down"):
        down = 0
    if (str(key)=="Escape" and done==1):
        root.quit
        do = 0
        lives = -1
        root.quit()
    if (str(key)=="p"):
        if(pause==1):
            pause=0
        elif(pause==0):
            pause=1
def buttononit():
    root.bind("<Up>",high)
    root.bind("<Down>",low)
    root.bind("`",leave)
    root.bind('<KeyRelease>', offkeyrelease)
buttononit()


c.create_text(475,10,text='Lives:',fill='white',font=font)
livestext = c.create_text(525,10,text=lives,fill='white',font=font)
c.create_text(475,25,text='Score:',fill='white',font=font)
scoretext = c.create_text(525,25,text=score,fill='white',font=font)
print "Push 'p' to pause"
var=1

while (do):
    ##  player movement controls
    if(playerone>0 and up==1 and down!=1 and pause==0):
        playerone=playerone-5
    if(playerone<360 and down==1 and up!=1 and pause==0):
        playerone=playerone+5

##  player collision detection
    if(ballX>=605 and ballY+10>=playerone and ballX<=616 and ballY+10>=playerone and ballY-10<=playerone+120):
        xc*=-1
        ballX=605
        if(xc>-10):
            xc=float(xc)-float(0.4)
        if(yc>0):
            yc=float(random.randint(15,70))
            yc=float(yc)/float(10)
        else: 
            yc=float(random.randint(-70,-15))
            yc=float(yc)/float(10)

##  playertwo movement controls
        if (playertwo>0 and high==1 and low!=1 and pause==0):
            playertwo=playertwo+5
        if (playertwo<360 and low==1 and high!=1 and pause==0):
            playertwo=playertwo-5

##  playertwo collision detection
    if(ballX<=40 and ballX>=29 and ballY+py2 and ballY-10<=py2+120):
        xc*=-1
        ballX=40
        if(xc<10):
            xc=float(xc)+float(0.4)
        if(yc>0):
            yc=float(random.randint(15,70))
            yc=float(yc)/float(10)
        else:
            yc=float(random.randint(-70,-15))
            yc=float(yc)/float(10)

##  left and right bounds collision detection (aka missed paddle)
    if(ballX>=630 and xc>0):
        ballX=320
        ballY=240
        xc = 2
        yc = random.randint(-3,3)
        while(yc==0):
            yc = random.randint(-3,3)
        lives = lives-1
        escore=escore+1
    if(ballX<=10 and xc<0):
        ballX=320
        ballY=240
        xc = 2
        yc = random.randint(-3,3)
        while(yc==0):
            yc = random.randint(-3,3)
        score=score+1

##  top and bottom bounds colliison detection
    if(playerone<0):
        playerone=0
    if(playerone>360):
        playerone=360
    if(ballY>=470 or ballY<=10):
        yc*=-1

##  AI(artificial intelligence(ball)) movement controls
    if(py2+60<ballY and py2<360 and xc<0 and pause==0):
        py2=py2+4
    if(py2+60>ballY and py2>0 and xc<0 and pause==0):
        py2=py2-4
    if(pause==0):
        ballX=ballX+xc
        ballY=ballY+yc
    c.delete(ball)
    ball = c.create_oval(ballX-10,ballY-10,ballX+10,ballY+10,fill='white')
    c.delete(player)
    player = c.create_rectangle(610,playerone,625,playerone+120,fill='blue')
    c.delete(playertwo)

# to change the game to single player, remove the playerone's in the following line and replace them with py2's
# this are  the coordinates for the paddle
# the first playerone, tracks the position of the thing that the paddle is following
# 1#= how wide it is, 2# tracks the other object, 3# the width, 4# how tall the paddle is, 5# the color

    playertwo = c.create_rectangle(15, playerone ,30,  playerone + 120 ,fill='blue')

    c.delete(livestext)
    livestext = c.create_text(525,10,text=lives,fill='white',font=font)
    c.delete(scoretext)
    scoretext = c.create_text(525,25,text=score,fill='white',font=font)
    c.update()
    time.sleep(Decimal("1")/Decimal("100"))
    if(lives==0):
        do=0
        if(score > 0):
            print score
        done = 1
    try:
        c.update()
    except:
        print "Error"
        root.quit
    while(lives==0):
        c.update()
try:
    c.update()
except:
    print "Error!!!"
    root.quit

问题答案:

您的代码已被改编为以下两人游戏。该程序已重组为各种功能,类和方法。没有AI时,控件是相同的。

from tkinter import *
from tkinter.font import Font
import functools
import math
import random
import time; time.clock = time.perf_counter

################################################################################

class Pong(Canvas):

    DEFAULTS = dict(width=640,
                    height=480,
                    background='black',
                    highlightthickness=0)

    @classmethod
    def main(cls):
        root = Tk()
        root.title('Pong')
        root.resizable(False, False)
        root.bind_all('<Escape>', lambda event: root.destroy())
        game = cls(Font(family='Book Antiqua', size=15, weight='bold'), 5, 100,
                   background='black', width=640, height=480)
        game.grid()
        root.mainloop()

    def __init__(self, font, lives, fps, master=None, cnf={}, **kw):
        for item in self.DEFAULTS.items():
            kw.setdefault(*item)
        super().__init__(master, cnf, **kw)
        self.font = font
        self.p1 = Paddle(lives, 'blue', 10,
                         self.height, 120, 15, 5)
        self.p2 = Paddle(lives, 'blue', self.width - 10,
                         self.height, 120, 15, 5)
        self.wait = 1000 // fps
        self.separator = Box(Point(self.width // 2 - 2, 0),
                             Point(self.width // 2 + 2, self.height))
        self.new_rect(self.separator, 'white')
        self.bind('<p>', self.pause)
        self.p1.bind(self, 'w', 's')
        self.p2.bind(self, 'Up', 'Down')
        self.draw_high = True
        self.after_idle(self.startup)
        self.focus_force()

    def pause(self, event):
        if not self.running_startup:
            self.refresh = self.after_cancel(self.refresh) \
                           if self.refresh else self.after_idle(self.animate)

    def startup(self, countdown=3, target=None):
        if target is None:
            self.running_startup = True
            self.ball = Ball('white', self.width, self.height, 20)
            self.refresh = None
            target = time.clock() + countdown
        for paddle in self.p1, self.p2:
            paddle.center()
        self.draw_all()
        remaining = math.ceil(target - time.clock())
        if remaining:
            self.new_text(Point(self.width >> 1, self.height >> 1),
                          self.random_color(), str(remaining), CENTER)
            self.after(self.wait, self.startup, None, target)
        else:
            self.running_startup = False
            self.after_idle(self.animate)

    @classmethod
    def random_color(cls):
        return '#{:02X}{:02X}{:02X}'.format(*cls.random_bytes(3))

    @staticmethod
    def random_bytes(n):
        return bytes(random.randrange(1 << 8) for _ in range(n))

    def animate(self):
        self.move_all()
        if self.in_bounds():
            self.draw_all()
            self.refresh = self.after(self.wait, self.animate)

    def move_all(self):
        for obj in self.p1, self.p2, self.ball:
            obj.move()
            if obj is not self.ball:
                obj.bounce(self.ball)

    def in_bounds(self):
        if self.boundary.intersects(self.ball.boundary):
            return True
        if (self.p2 if self.ball.position.x > 0 else self.p1).kill():
            self.after_idle(self.startup)
        else:
            self.draw_all()
            self.after(5000, self.quit)
        return False

    def draw_all(self):
        self.delete('actor')
        for obj in self.p1, self.p2, self.ball:
            obj.render(self)
        self.render_status()

    def render_status(self, x_margin=4, y_margin=4):
        self.draw_high = high = (self.ball.position.y > self.height * 0.25) \
                                if self.draw_high else \
                                (self.ball.position.y >= self.height * 0.75)
        if high:
            self.new_text(self.separator.NW + Point(-x_margin, +y_margin),
                          'white', self.p1.status, NE)
            self.new_text(self.separator.NE + Point(+x_margin, +y_margin),
                          'white', self.p2.status, NW)
        else:
            self.new_text(self.separator.SW + Point(-x_margin, -y_margin),
                          'white', self.p1.status, SE)
            self.new_text(self.separator.SE + Point(+x_margin, -y_margin),
                          'white', self.p2.status, SW)

    def new_rect(self, box, color, tag='static'):
        self.create_rectangle(box, fill=color, outline=color, tag=tag)

    def new_oval(self, box, color, tag='static'):
        self.create_oval(box, fill=color, outline=color, tag=tag)

    def new_text(self, point, color, text, anchor, tag='actor'):
        self.create_text(point, fill=color, tag=tag,
                         text=text, anchor=anchor, font=self.font)

    @property
    def width(self):
        return int(self['width'])

    @property
    def height(self):
        return int(self['height'])

    @property
    def boundary(self):
        return Box(Point(0, 0), Point(self.width, self.height))

################################################################################

def enum(names):
    return type('enum', (), dict(map(reversed, enumerate(
        names.replace(',', ' ').split())), __slots__=()))()

def copy_sign(x, y):
    return type(x)(math.copysign(x, y))

################################################################################

class Paddle:

    PART = enum('null, upper, center, lower')

    def __init__(self, lives, color, alignment, board_height,
                 paddle_height, paddle_width, move_by):
        self.lives = lives
        self.color = color
        self.height = board_height
        self.position = Point(alignment, board_height >> 1)
        self.size = Point(paddle_width >> 1, paddle_height >> 1)
        self.move_by = move_by
        self.score = 0
        self.just_bounced = False

    def kill(self):
        self.lives -= 1
        self.score >>= 1
        return self.lives > 0

    def center(self):
        y, middle = self.position.y, self.height >> 1
        if y < middle:
            self.move(down=True)
        elif y > middle:
            self.move(up=True)

    def move(self, *, up=False, down=False):
        if up or (not down and self.keys.up and
                  self.position.y - self.size.y > 0):
            self.position -= Point(0, self.move_by)
        if down or (not up and self.keys.down and
                    self.position.y + self.size.y < self.height):
            self.position += Point(0, self.move_by)

    def bounce(self, ball):
        minimum = self.size.x + ball.radius
        if self.position.x != ball.position.x and self.overlap(ball, minimum):
            if not self.just_bounced:
                self.just_bounced = True
                self.score += abs(ball.velocity.y)
            sign = +1 if self.position.x < ball.position.x else -1
            if self.collision_area == self.PART.center:
                ball.position.x = self.position.x + minimum * sign
            else:
                ball.position.adjust(self.middle_point, minimum)
            ball.velocity.x = copy_sign(ball.velocity.x, sign)
            ball.change_speed()
        else:
            self.just_bounced = False

    def overlap(self, ball, minimum):
        box = self.boundary
        if box.intersects(ball.boundary):
            self.collision_area = self.PART.center
        elif (self.hi_mid(box) - ball.position).magnitude <= minimum:
            self.collision_area = self.PART.upper
        elif (self.lo_mid(box) - ball.position).magnitude <= minimum:
            self.collision_area = self.PART.lower
        else:
            self.collision_area = self.PART.null
        return self.collision_area

    def render(self, surface):
        box = self.boundary
        surface.new_rect(box, self.color, 'actor')
        surface.new_oval(Box.from_point(self.hi_mid(box), self.size.x),
                         self.color, 'actor')
        surface.new_oval(Box.from_point(self.lo_mid(box), self.size.x),
                         self.color, 'actor')

    def hi_mid(self, boundary):
        self.middle_point = Point(self.position.x, boundary.a.y)
        return self.middle_point

    def lo_mid(self, boundary):
        self.middle_point = Point(self.position.x, boundary.b.y)
        return self.middle_point

    def bind(self, surface, up, down):
        self.keys = KeyListener(surface, up=up, down=down)

    @property
    def boundary(self):
        return Box.from_point(self.position, self.size)

    @property
    def status(self):
        return 'Lives: {}\nScore: {}'.format(self.lives, self.score)

Player = Paddle

################################################################################

class KeyListener:

    def __init__(self, widget, **kwargs):
        self.__state = dict.fromkeys(kwargs, False)
        for name, key in kwargs.items():
            widget.bind('<KeyPress-{}>'.format(key), self.__set(name, True))
            widget.bind('<KeyRelease-{}>'.format(key), self.__set(name, False))

    def __set(self, name, value):
        def handler(event):
            self.__state[name] = value
        return handler

    def __getattr__(self, name):
        return self.__state[name]

################################################################################

class Ball:

    def __init__(self, color, width, height, size):
        self.color = color
        self.board = Point(width, height)
        self.position = self.board / 2
        self.radius = size >> 1
        self.velocity = Point(1 - 2 * random.randrange(2),
                              1 - 2 * random.randrange(2))
        self.change_speed()

    def change_speed(self, max_x=10, max_y=10):
        speed = self.velocity
        speed.x = copy_sign(random.randint(1, max_x), speed.x)
        speed.y = copy_sign(random.randint(1, max_y), speed.y)

    def move(self):
        self.position += self.velocity
        self.bounce()

    def bounce(self):
        if self.position.y - self.radius < 0:
            self.position.y = self.radius
            self.velocity.y = copy_sign(self.velocity.y, +1)
            self.change_speed()
        elif self.position.y + self.radius > self.board.y:
            self.position.y = self.board.y - self.radius
            self.velocity.y = copy_sign(self.velocity.y, -1)
            self.change_speed()

    def render(self, surface):
        surface.new_oval(self.boundary, self.color, 'actor')

    @property
    def boundary(self):
        return Box.from_point(self.position, self.radius)

################################################################################

def autocast(function):
    @functools.wraps(function)
    def cast(self, other):
        if not isinstance(other, self.__class__):
            other = self.__class__(other, other)
        return function(self, other)
    return cast

################################################################################

class Point(list):

    def __init__(self, x, y):
        super().__init__((x, y))

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__,
                               ', '.join(map(repr, self)))

    @autocast
    def __add__(self, other):
        return self.__class__(self.x + other.x, self.y + other.y)

    @autocast
    def __sub__(self, other):
        return self.__class__(self.x - other.x, self.y - other.y)

    @autocast
    def __mul__(self, other):
        return self.__class__(self.x * other.x, self.y * other.y)

    @autocast
    def __truediv__(self, other):
        return self.__class__(self.x / other.x, self.y / other.y)

    @autocast
    def __floordiv__(self, other):
        return self.__class__(self.x // other.x, self.y // other.y)

    @autocast
    def __iadd__(self, other):
        self.x += other.x
        self.y += other.y
        return self

    @autocast
    def __isub__(self, other):
        self.x -= other.x
        self.y -= other.y
        return self

    def __get_x(self):
        return self[0]

    def __set_x(self, value):
        self[0] = value

    x = property(__get_x, __set_x)

    def __get_y(self):
        return self[1]

    def __set_y(self, value):
        self[1] = value

    y = property(__get_y, __set_y)

    def __get_magnitude(self):
        return math.hypot(self.x, self.y)

    def __set_magnitude(self, value):
        magnitude = self.magnitude
        self.x *= value / magnitude
        self.y *= value / magnitude

    magnitude = property(__get_magnitude, __set_magnitude)

    def adjust(self, projected_from, distance):
        vector = self - projected_from
        vector.magnitude = distance
        self.x = round(projected_from.x + vector.x)
        self.y = round(projected_from.y + vector.y)

################################################################################

class Box(list):

    @classmethod
    def from_point(cls, point, extension):
        return cls(point - extension, point + extension)

    def __init__(self, a, b):
        super().__init__((a, b))

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__,
                               ', '.join(map(repr, self)))

    def intersects(self, other):
        return not (self.a.x > other.b.x or other.a.x > self.b.x or
                    self.a.y > other.b.y or other.a.y > self.b.y)

    def __get_a(self):
        return self[0]

    def __set_a(self, value):
        self[0] = value

    a = NW = property(__get_a, __set_a)

    def __get_b(self):
        return self[1]

    def __set_b(self, value):
        self[1] = value

    b = SE = property(__get_b, __set_b)

    @property
    def NE(self):
        return Point(self.b.x, self.a.y)

    @property
    def SW(self):
        return Point(self.a.x, self.b.y)

################################################################################

if __name__ == '__main__':
    Pong.main()

Edit: In designing the scoring system, it did not make sense to have a
score and lives. If a player’s score is incremented by one when the opponent
looses, scores could be dropped, and the winner would be the person who did
not loose all lives. If a player’s score is incremented by one each time the
ball is hit, both players will have nearly identical scores throughout the
game, and the scores are fairly meaningless.


I chose to increment a player’s score based on an approximation of how
difficult the ball was to hit. If the ball happened to have a vertical
movement of five and the player hits the ball, then the player’s score is
incremented by five. To add further incentive not to loose lives, a player’s
score is halved upon loosing a life. That also provides ample opportunity for
the other player to catch up in scoring.

As for the weird bouncing, the ball will have a random change in speed each
time it hits an object. The reason for this is that if the ball stayed at the
same speed and bounced normally, it would be very easy to predict where the
ball was going to go, and the game would be too easy. If the player finds no
challenge in the game, being bored and invincible would lead to rapid
abandonment of the game.

The status display moves to the opposite side of the board when the ball gets
close enough so that the status and ball never end up on top of each other,
confusing potential players. The change is triggered by the ball’s moving up
past 25% screen height or the ball’s moving down past 75% screen height. If
there is anything that you feel should be different about the game, please
consider learning Python so that you can modify the game yourself.



 类似资料:
  • 所以我试着在处理过程中对乒乓球进行编码,一切正常,我可以完美地上下移动球拍,但是,当你试图同时移动两个球拍时,他们不动/它不让你动(我将把这变成一个两人游戏,这样两个人可以使用同一个键盘,但不同的按键可以玩不同的桨)。 我认为这是使用“key”或“keyPressed”的问题,因为我认为它不能同时检测这两个或其他东西?但我似乎不知道如何解决这个问题或任何替代方案。(请记住,我知道如何移动桨叶,只是

  • 本教程将教你如何使用 Kivy 编写一款乒乓球游戏。我们将从一个基本的应用程序开始,描述创建这个游戏的每个步骤。 Kivy 是用 Python 和 Cython 编写的,基于 OpenGL ES 2,支持各种输入设备并拥有丰富的部件库。使用相同的代码,你可直接实现多平台应用,包括 Windows、macOS、Linux、Android 和 iOS。所有 Kivy 部件都支持多点触控。

  • 我试图用Java创建一个简单的乒乓球游戏进行处理。我还没有完成,一切都很顺利,只是我不能让球从乒乓桨上反弹。我已经成功地做到了,如果球低于桨板,它会反弹回来,但出于某种原因,如果球高于桨板,它会穿过。 paddleFunctions选项卡:

  • 本文向大家介绍如果用乒乓球塞满一个教室,请你估算所需乒乓球数量。相关面试题,主要包含被问及如果用乒乓球塞满一个教室,请你估算所需乒乓球数量。时的应答技巧和注意事项,需要的朋友参考一下 先计算乒乓球的体积:由于测量麻烦,就用一杯水,把乒乓球塞进去,测量溢出水的体积。 再计算乒乓球的直径。 测量教室的宽、高。分别用宽/乒乓球直径=n(取整),高/乒乓球直径=m(取整)。 再用教室的长/乒乓球直径=x(

  • 我想做一个正在处理的乒乓球游戏。但是球的移动不是很平稳。我试着改变帧速率并降低球的速度,但是移动速度似乎不是恒定的。这可能是性能问题吗?我是否做错了什么,或者即使对于简单的游戏,处理可能也不是正确的事情?(我的目标是试用processing.js,制作一款没有插件的游戏)。这是我的代码:

  • 我有三节课: 人类 父亲 孩子。 儿童阶级延伸父亲,父亲延伸人类。 我已经创建了每个类的一些实例并将它们存储到ArrayList中。 现在,我想编写一个方法来检查对象father1是否与对象child1地址字段(类Father和Child的实例)具有相同的字段地址(例如:“21 str Goodwin”),并将此方法提供给我的ArrayList,如果发现任何结果,则打印。 我怎么能这样呢? 为了更