所以我发现这个名叫法拉利的球员创造了一场伟大的乒乓球比赛,我被赋予了两个得分,但没有高分的任务。我已经尝试了很多东西,除非我制作了第二块控制动作的代码,它要么被完全忽略,要么我按下它分配的向上按钮,它将一直向上,不会再回来。
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
答案 0 :(得分:2)
您的代码已经重新设计为以下双人游戏。该程序已被重组为各种函数,类和方法。控件是相同的,没有AI可以使用。
from tkinter import *
from tkinter.font import Font
import functools
import math
import random
import time
################################################################################
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()
编辑:在设计评分系统时,得分和生命没有意义。如果当对手失去时球员的得分增加1,则得分可以被丢弃,并且获胜者将是没有失去所有生命的人。如果每次击球时球员的得分增加1,则两个球员在整个比赛中的得分几乎相同,并且得分相当无意义。
我选择根据近似击球的难度来增加球员的得分。如果球碰巧有五个垂直移动并且球员击球,则球员的得分增加五。为了进一步激励不要放松生命,玩家的分数在失去生命后减半。这也为其他球员提供了充分的机会来赶上得分。
对于奇怪的弹跳,每次撞击物体时球的速度都会随机变化。这样做的原因是,如果球保持相同的速度并且正常弹跳,那么很容易预测球将要去哪里,而且比赛太简单了。如果玩家在游戏中没有发现任何挑战,那么无聊和无敌会导致游戏迅速放弃。
当球足够接近时,状态显示移动到棋盘的另一侧,以便状态和球永远不会相互叠加,从而使潜在的球员感到困惑。球的移动超过25%的屏幕高度或球向下移动超过75%的屏幕高度,从而触发更改。如果您认为游戏中存在任何不同之处,请考虑学习Python,以便您自己修改游戏。