检测乌龟/乌龟和乌龟线之间的碰撞

发布于 2025-02-09 02:16:59 字数 7643 浏览 0 评论 0原文

因此,我正在用乌龟编码Tron游戏,而我需要做的最后一部分是在乌龟本身,碰撞的碰撞以及A Turtle和另一只乌龟制造的界线之间进行编码。我对束缚的碰撞进行了编码,但它们没有起作用,我还尝试对玩家进行编码,以防止玩家碰撞也没有起作用。我不知道如何做另一个(当乌龟与另一只乌龟产生的线相撞时,它会输出某些东西)。我想到了以某种方式使用数组,但我不确定这些数组如何工作。谁能帮我吗?

淘汰碰撞的代码:

#Width and height of the screen
width = turtle.window_width()
height = turtle.window_height()

def collisions():
    while True:
      if(math.isclose(blue_player.xcor(), red_player.xcor(), abs_tol=1e-10) and
       math.isclose(blue_player.ycor(), red_player.ycor(), abs_tol=1e-10)):
        TurtleCrash = turtle.Turtle(visible=False)
        TurtleCrash.color("white")
        style = ('Arial', 25, 'italic')
        TurtleCrash.write("Red and Blue Crashed!\nGame over!", font=style, align='center')
        break
         
      if blue_player.xcor() > width or blue_player.xcor() < -1*width:
        BlueTurtleOut = turtle.Turtle(visible=False)
        BlueTurtleOut.color("white")
        style = ('Arial', 25, 'italic')
        BlueTurtleOut.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
        
      if blue_player.ycor() > height or blue_player.ycor() < -1*height:
        BlueTurtleOut2 = turtle.Turtle(visible=False)
        BlueTurtleOut2.color("white")
        style = ('Arial', 25, 'italic')
        BlueTurtleOut2.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
  
      if red_player.xcor() > width or red_player.xcor() < -1*width:
        RedTurtleOut = turtle.Turtle(visible=False)
        RedTurtleOut.color("white")
        style = ('Arial', 25, 'italic')
        RedTurtleOut.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
  
      if red_player.ycor() > height or red_player.ycor() < -1*height:
        RedTurtleOut2 = turtle.Turtle(visible=False)
        RedTurtleOut2.color("white")
        style = ('Arial', 25, 'italic')
        RedTurtleOut2.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
    gameScreen()

GamesCreen是我代码中早期调用的功能,但这不是问题,尽管它可能位于函数中的位置错误。我不知道。

没有人获胜的海龟之间(未遂)碰撞的代码。

collision = turtle.Turtle()
collision.hideturtle()

if blue_player.pos() == red_player.pos():
    collision.goto(0,0)
    collision.showturtle()
    collision.write("You collided with each other!\nIt's a tie!")

这是完整的代码:

#Width and height of the screen
width = turtle.window_width()
height = turtle.window_height()

#Variables for tron game coded later on
red_direction = None
blue_direction = None

def TronGame():
    #Border
    #box = Turtle()
    #box.ht()
    #box.color('purple')
    #box.speed('fastest')
    #box.pensize(10)

   # box.pu()
   # box.goto(-1*height, -1*width)
   # box.pd()

   # for i in range(4):
   #   box.forward(height)
   #   box.left(90)
   #   box.forward(width)
   #   box.left(90)
      
  #Blue Player movements
  def blue_up():  
      global blue_direction
      blue_direction = 'up'
    
  def blue_down():
      global blue_direction
      blue_direction = 'down'
    
  def blue_left():
      global blue_direction
      blue_direction = 'left'
    
  def blue_right():
      global blue_direction
      blue_direction = 'right'

  #Red player Movemnts 
  def red_up():   
      global red_direction
      red_direction = 'up'
    
  def red_down():
      global red_direction
      red_direction = 'down'
    
  def red_left():
      global red_direction
      red_direction = 'left'
    
  def red_right():
      global red_direction
      red_direction = 'right'

  #Player movements   
  def move_player(player, direction):
      if direction == 'up':
          player.setheading(90)
          player.forward(5)
      elif direction == 'down':
          player.setheading(270)
          player.forward(5)
      elif direction == 'left':
          player.setheading(180)
          player.forward(5)
      elif direction == 'right':
          player.setheading(0)
          player.forward(5)

  def gameloop():
      move_player(red_player, red_direction)
      move_player(blue_player, blue_direction)
    
      #Repeat after 10ms (0.01s) (1000ms/10ms = 100 FPS)
      screen.ontimer(gameloop, 10)

  def collisions():
    while True:
      if(math.isclose(blue_player.xcor(), red_player.xcor(), abs_tol=1e-10) and
       math.isclose(blue_player.ycor(), red_player.ycor(), abs_tol=1e-10)):
        TurtleCrash = turtle.Turtle(visible=False)
        TurtleCrash.color("white")
        style = ('Arial', 25, 'italic')
        TurtleCrash.write("Red and Blue Crashed!\nGame over!", font=style, align='center')
        break
         
      if blue_player.xcor() > width or blue_player.xcor() < -1*width:
        BlueTurtleOut = turtle.Turtle(visible=False)
        BlueTurtleOut.color("white")
        style = ('Arial', 25, 'italic')
        BlueTurtleOut.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
        
      if blue_player.ycor() > height or blue_player.ycor() < -1*height:
        BlueTurtleOut2 = turtle.Turtle(visible=False)
        BlueTurtleOut2.color("white")
        style = ('Arial', 25, 'italic')
        BlueTurtleOut2.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
  
      if red_player.xcor() > width or red_player.xcor() < -1*width:
        RedTurtleOut = turtle.Turtle(visible=False)
        RedTurtleOut.color("white")
        style = ('Arial', 25, 'italic')
        RedTurtleOut.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
  
      if red_player.ycor() > height or red_player.ycor() < -1*height:
        RedTurtleOut2 = turtle.Turtle(visible=False)
        RedTurtleOut2.color("white")
        style = ('Arial', 25, 'italic')
        RedTurtleOut2.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break


  def MainTron():
    global screen
    global blue_player
    global red_player
  
    screen = turtle.Screen()
    screen.setup(width, height)
    screen.bgpic('TronBg.png')
    screen.bgcolor('black')
    screen.addshape('BlueBike.gif')
    screen.addshape('RedBike.gif')

    blue_player = turtle.Turtle()
    blue_player.shape('BlueBike.gif')
    blue_player.pencolor("blue")
    blue_player.pensize(3)
    blue_player.pu()
    blue_player.goto(-1*(width)/3, height/8)
    blue_player.pd()

    red_player = turtle.Turtle()
    red_player.shape('RedBike.gif')
    red_player.pencolor("red")
    red_player.pensize(3)
    red_player.pu()
    red_player.goto(width/3, height/8)
    red_player.pd()

    for x in range(10):
      my_turtle = turtle.Turtle(visible=False)
      my_turtle.color("white")
      style = ('Arial', 25, 'italic')
      my_turtle.write(10-x, font=style, align='center') 
      time.sleep(1)
      my_turtle.undo()
  
    screen.listen()

    #collisions()
        
    screen.onkey(red_up, "w")
    screen.onkey(red_down, "s")
    screen.onkey(red_left, "a")
    screen.onkey(red_right, "d")
  
    screen.onkey(blue_up, "Up")
    screen.onkey(blue_down, "Down")
    screen.onkey(blue_left, "Left")
    screen.onkey(blue_right, "Right")

    screen.ontimer(gameloop, 250)


    #collision = turtle.Turtle()
    #collision.hideturtle()

    #if blue_player.pos() == red_player.pos():
    #  collision.goto(0,0)
    #  collision.showturtle()
    #  collision.write("You collided with each other!\nIt's a tie!")
    
    screen.mainloop()

  MainTron()

So I'm coding a tron game in turtle and the last part I need to do is to code the collisions between the turtles themselves, out of bound collisions, and collisions between the line made by the a turtle and the other turtle. I coded the out of bound collisions and they didn't work, and I also tried coding the player against player collisions which didn't work either. I've got no clue how to do the other one (where it outputs something when the turtle collides with the line generated by the other turtle). I thought of using an array in some way but I'm not sure how those work. Can anyone help me out?

Code for the out of bound collisions:

#Width and height of the screen
width = turtle.window_width()
height = turtle.window_height()

def collisions():
    while True:
      if(math.isclose(blue_player.xcor(), red_player.xcor(), abs_tol=1e-10) and
       math.isclose(blue_player.ycor(), red_player.ycor(), abs_tol=1e-10)):
        TurtleCrash = turtle.Turtle(visible=False)
        TurtleCrash.color("white")
        style = ('Arial', 25, 'italic')
        TurtleCrash.write("Red and Blue Crashed!\nGame over!", font=style, align='center')
        break
         
      if blue_player.xcor() > width or blue_player.xcor() < -1*width:
        BlueTurtleOut = turtle.Turtle(visible=False)
        BlueTurtleOut.color("white")
        style = ('Arial', 25, 'italic')
        BlueTurtleOut.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
        
      if blue_player.ycor() > height or blue_player.ycor() < -1*height:
        BlueTurtleOut2 = turtle.Turtle(visible=False)
        BlueTurtleOut2.color("white")
        style = ('Arial', 25, 'italic')
        BlueTurtleOut2.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
  
      if red_player.xcor() > width or red_player.xcor() < -1*width:
        RedTurtleOut = turtle.Turtle(visible=False)
        RedTurtleOut.color("white")
        style = ('Arial', 25, 'italic')
        RedTurtleOut.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
  
      if red_player.ycor() > height or red_player.ycor() < -1*height:
        RedTurtleOut2 = turtle.Turtle(visible=False)
        RedTurtleOut2.color("white")
        style = ('Arial', 25, 'italic')
        RedTurtleOut2.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
    gameScreen()

gameScreen is a function called earlier in my code by the way, it's not the issue, although it could be in the wrong place in the function. I'm not sure.

Code for (attempted) collision between the turtles where nobody wins.

collision = turtle.Turtle()
collision.hideturtle()

if blue_player.pos() == red_player.pos():
    collision.goto(0,0)
    collision.showturtle()
    collision.write("You collided with each other!\nIt's a tie!")

Here's the full code:

#Width and height of the screen
width = turtle.window_width()
height = turtle.window_height()

#Variables for tron game coded later on
red_direction = None
blue_direction = None

def TronGame():
    #Border
    #box = Turtle()
    #box.ht()
    #box.color('purple')
    #box.speed('fastest')
    #box.pensize(10)

   # box.pu()
   # box.goto(-1*height, -1*width)
   # box.pd()

   # for i in range(4):
   #   box.forward(height)
   #   box.left(90)
   #   box.forward(width)
   #   box.left(90)
      
  #Blue Player movements
  def blue_up():  
      global blue_direction
      blue_direction = 'up'
    
  def blue_down():
      global blue_direction
      blue_direction = 'down'
    
  def blue_left():
      global blue_direction
      blue_direction = 'left'
    
  def blue_right():
      global blue_direction
      blue_direction = 'right'

  #Red player Movemnts 
  def red_up():   
      global red_direction
      red_direction = 'up'
    
  def red_down():
      global red_direction
      red_direction = 'down'
    
  def red_left():
      global red_direction
      red_direction = 'left'
    
  def red_right():
      global red_direction
      red_direction = 'right'

  #Player movements   
  def move_player(player, direction):
      if direction == 'up':
          player.setheading(90)
          player.forward(5)
      elif direction == 'down':
          player.setheading(270)
          player.forward(5)
      elif direction == 'left':
          player.setheading(180)
          player.forward(5)
      elif direction == 'right':
          player.setheading(0)
          player.forward(5)

  def gameloop():
      move_player(red_player, red_direction)
      move_player(blue_player, blue_direction)
    
      #Repeat after 10ms (0.01s) (1000ms/10ms = 100 FPS)
      screen.ontimer(gameloop, 10)

  def collisions():
    while True:
      if(math.isclose(blue_player.xcor(), red_player.xcor(), abs_tol=1e-10) and
       math.isclose(blue_player.ycor(), red_player.ycor(), abs_tol=1e-10)):
        TurtleCrash = turtle.Turtle(visible=False)
        TurtleCrash.color("white")
        style = ('Arial', 25, 'italic')
        TurtleCrash.write("Red and Blue Crashed!\nGame over!", font=style, align='center')
        break
         
      if blue_player.xcor() > width or blue_player.xcor() < -1*width:
        BlueTurtleOut = turtle.Turtle(visible=False)
        BlueTurtleOut.color("white")
        style = ('Arial', 25, 'italic')
        BlueTurtleOut.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
        
      if blue_player.ycor() > height or blue_player.ycor() < -1*height:
        BlueTurtleOut2 = turtle.Turtle(visible=False)
        BlueTurtleOut2.color("white")
        style = ('Arial', 25, 'italic')
        BlueTurtleOut2.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
  
      if red_player.xcor() > width or red_player.xcor() < -1*width:
        RedTurtleOut = turtle.Turtle(visible=False)
        RedTurtleOut.color("white")
        style = ('Arial', 25, 'italic')
        RedTurtleOut.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break
  
      if red_player.ycor() > height or red_player.ycor() < -1*height:
        RedTurtleOut2 = turtle.Turtle(visible=False)
        RedTurtleOut2.color("white")
        style = ('Arial', 25, 'italic')
        RedTurtleOut2.write("Red went out of bounds./nBlue wins!", font=style, align='center')
        break


  def MainTron():
    global screen
    global blue_player
    global red_player
  
    screen = turtle.Screen()
    screen.setup(width, height)
    screen.bgpic('TronBg.png')
    screen.bgcolor('black')
    screen.addshape('BlueBike.gif')
    screen.addshape('RedBike.gif')

    blue_player = turtle.Turtle()
    blue_player.shape('BlueBike.gif')
    blue_player.pencolor("blue")
    blue_player.pensize(3)
    blue_player.pu()
    blue_player.goto(-1*(width)/3, height/8)
    blue_player.pd()

    red_player = turtle.Turtle()
    red_player.shape('RedBike.gif')
    red_player.pencolor("red")
    red_player.pensize(3)
    red_player.pu()
    red_player.goto(width/3, height/8)
    red_player.pd()

    for x in range(10):
      my_turtle = turtle.Turtle(visible=False)
      my_turtle.color("white")
      style = ('Arial', 25, 'italic')
      my_turtle.write(10-x, font=style, align='center') 
      time.sleep(1)
      my_turtle.undo()
  
    screen.listen()

    #collisions()
        
    screen.onkey(red_up, "w")
    screen.onkey(red_down, "s")
    screen.onkey(red_left, "a")
    screen.onkey(red_right, "d")
  
    screen.onkey(blue_up, "Up")
    screen.onkey(blue_down, "Down")
    screen.onkey(blue_left, "Left")
    screen.onkey(blue_right, "Right")

    screen.ontimer(gameloop, 250)


    #collision = turtle.Turtle()
    #collision.hideturtle()

    #if blue_player.pos() == red_player.pos():
    #  collision.goto(0,0)
    #  collision.showturtle()
    #  collision.write("You collided with each other!\nIt's a tie!")
    
    screen.mainloop()

  MainTron()

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

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

发布评论

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

评论(2

落叶缤纷 2025-02-16 02:16:59

正如约翰尼·莫普(Johnny Mopp)已经提到的那样,有很多改进代码的地方。在一个肯定的不完整列表下,仅描述了对原始代码进行的许多更改的一部分以及简短的说明以及对python功能的描述的变化如何改善这些更改:

  • 如果函数返回的值多次使用的值最好先将其值分配给变量,然后
  • 将空字符串s =“”视为python(bool(“”)是false)。这允许将字符串用作指示
  • 在钥匙压上发现的碰撞的标志,乌龟可以直接获得其方向。无需在“向上”和90之间进行第四和返回。
  • 在简单的情况下,函数嵌套或使用类,使代码变得更糟,更难理解,而不是更好地理解我已经完全“平坦”了代码。
  • 尽可能地消除了完全相同的代码,一次又一次地
  • 将属于彼此靠近的东西放在代码中
  • 增加了通过按“ Space”按钮暂停/重新启动游戏的可能性。
  • 设置检测碰撞的阈值,因此现在检测到玩家的崩溃
  • 将宽度和高度值设置为一半,因此现在检测到屏幕边缘的碰撞,
  • 考虑到Python中,您可以编写好看和直观的min&lt ; x&lt;最大而不是min&lt; x和x&lt; Max我决定将其用于检测碰撞,但不是作为检查播放器是否在屏幕区域之外的检查(因为表达式max&lt; x&lt; min不起作用),但如果他在内部。如果玩家不再内部,则会发生碰撞。
  • 碰撞检测的另一个快捷方式是使用.distance()功能来检测玩家海龟之间的碰撞,而不是评估其坐标。
  • 添加了对轨迹的碰撞检测,玩家海龟在屏幕上留下的碰撞检测,以便现在检测到另一个玩家的路径。
  • Space'”来暂停和重新启动游戏的可能性

增加了通过按“ 碰撞检测部分中的代码通过另一种存储乌龟路径的克隆来替换乌龟的克隆,而另一种检测与路径下方的碰撞的方式

。代码正在运行:

“游戏背景图像”

import time, turtle
S_WIDTH, S_HEIGHT   = 1280, 850 # size of created Screen (window) 
PLAYER_MIN_DISTANCE = 15.0      # for collision between players
X_MIN, X_MAX = -S_WIDTH/2, S_WIDTH/2 # for collision of players with ... 
Y_MIN, Y_MAX = -S_HEIGHT/2, S_HEIGHT/2 # ... sides of the screen

# For displaying of messages to the user about game status (win/loss): 
message_turtle = turtle.Turtle(visible=False)
message_turtle.color("white")

red_clones  = []
blue_clones = []
CLONE_DIST  = PLAYER_MIN_DISTANCE/1.1
def check_collisions():
    global red_clones, blue_clones, game_running
    msg = "" # msg as not empty string will indicate collision

    if not any( blue_player.distance(blue_clone) < CLONE_DIST for blue_clone in  blue_clones):
        bpc = blue_player.clone(); bpc.hideturtle(); blue_clones.append( bpc )
    if not any( red_player.distance( red_clone ) < CLONE_DIST for red_clone  in  red_clones):
        rpc = red_player.clone();  rpc.hideturtle();  red_clones.append( rpc )

    for red_clone in red_clones: 
        if blue_player.distance(red_clone) < PLAYER_MIN_DISTANCE:
            msg = "Blue crashed in Red's path.\nRed wins!"
    for blue_clone in blue_clones:
        if red_player.distance(blue_clone) < PLAYER_MIN_DISTANCE:
            msg = "Red crashed in Blue's path.\nBlue wins!"
            
    if( blue_player.distance(red_player) < PLAYER_MIN_DISTANCE ): 
        msg = "Red and Blue Crashed!\nGame over!"

    if not ( X_MIN < blue_player.xcor() < X_MAX and Y_MIN < blue_player.ycor() < Y_MAX ):
        msg = "Blue went out of bounds.\nRed wins!"
    if not ( X_MIN < red_player.xcor() < X_MAX and Y_MIN < red_player.ycor() < Y_MAX ):
        msg = "Red went out of bounds.\nBlue wins!"

    if msg: 
        message_turtle.write( msg, font=('Arial', 25, 'italic'), align='center')
        pause_game()
        game_running = False
        del red_clones[:] ; del blue_clones[:]
        time.sleep(5)
        message_turtle.undo()
        blue_player.clear(); red_player.clear() 
        blue_player.is_moving=False; red_player.is_moving=False
        blue_player.pu();blue_player.goto(-1*S_WIDTH/3, S_HEIGHT/8);blue_player.pd()
        red_player.pu() ; red_player.goto(   S_WIDTH/3, S_HEIGHT/8); red_player.pd()
        blue_player.setheading(  0); red_player.setheading(180)
        message_turtle.write( "Press SPACE for a NEW GAME", font=('Arial', 25, 'italic'), align='center')
        countdown()
        if not game_paused:
            message_turtle.undo()
            game_running = True
        else: 
            screen.bye()
        
# Setting up the display area and making shapes available for later use 
screen = turtle.Screen()
screen.setup(S_WIDTH, S_HEIGHT)
# 
screen.bgpic(    'TronBg.png'  )
screen.bgcolor(  'green'       )
# screen.addshape( 'BlueBike.gif')
# screen.addshape( 'RedBike.gif' )

# Create the Blue Player Turtle and its controls 
blue_player = turtle.Turtle("turtle")
blue_player.shapesize(stretch_wid=3, stretch_len=3)
blue_player.setheading(  0)
# blue_player.shape('BlueBike.gif')
blue_player.pencolor("blue")
blue_player.pensize(15)
blue_player.pu()
blue_player.goto(-1*S_WIDTH/3, S_HEIGHT/8)
blue_player.pd()
blue_player.is_moving = False
def blue_up()   : blue_player.setheading( 90);blue_player.is_moving=True
def blue_down() : blue_player.setheading(270);blue_player.is_moving=True
def blue_left() : blue_player.setheading(180);blue_player.is_moving=True
def blue_right(): blue_player.setheading(  0);blue_player.is_moving=True
screen.onkey(blue_up,       "Up")
screen.onkey(blue_down,   "Down")
screen.onkey(blue_left,   "Left")
screen.onkey(blue_right, "Right")

# Create the Red Player Turtle and its controls 
red_player = turtle.Turtle("turtle")
red_player.shapesize(stretch_wid=3, stretch_len=3)
red_player.setheading(180)
# red_player.shape('RedBike.gif')
red_player.pencolor("red")
red_player.pensize(15)
red_player.pu()
red_player.goto(S_WIDTH/3, S_HEIGHT/8)
red_player.pd()
red_player.is_moving = False
def red_up()    : red_player.setheading( 90); red_player.is_moving=True
def red_down()  : red_player.setheading(270); red_player.is_moving=True
def red_left()  : red_player.setheading(180); red_player.is_moving=True
def red_right() : red_player.setheading(  0); red_player.is_moving=True
screen.onkey(red_up,         "w")
screen.onkey(red_down,       "s")
screen.onkey(red_left,       "a")
screen.onkey(red_right,      "d")

# Allow pausing the game by pressing space
game_paused = False
def pause_game():
    global game_paused
    if game_paused: game_paused = False
    else:           game_paused = True
screen.onkey(pause_game, "space")

# Countdown: 
countdown_turtle = turtle.Turtle(visible=False)
countdown_turtle.color("white")
countdown_turtle.goto(0, -50)
def countdown(): 
    for i in range(3,-1,-1):
        countdown_turtle.write(i, font=('Arial', 25, 'italic'), align='center') 
        time.sleep(1)
        countdown_turtle.undo()
countdown()

# Establishing a screen.ontimer() loop driving the turtles movement
game_running = True
def gameloop():
    if not game_paused and game_running:
        if blue_player.is_moving: blue_player.forward(3)
        if  red_player.is_moving:  red_player.forward(3)
        check_collisions()
    screen.ontimer(gameloop, 30) # 10ms (0.01s) (1000ms/10ms = 100 FPS)
gameloop()

# Start processing of key-presses
screen.listen()
screen.mainloop()

As Johnny Mopp already mentioned, there are lot of places to improve the code. Below a for sure incomplete list describing only part of the many changes done to the original code along with a short explanation what do the changes improve along with description of Python features making these changes possible:

  • If a value returned by a function is used multiple times it's better to assign its value to a variable first
  • An empty string s="" is considered False in Python (bool("") is False ). This allows to use the string as a flag indicating found collision
  • On key-press the Turtle can directly get its direction assigned. No need for a forth and back between "up" and 90.
  • As in simple cases nesting of functions or using classes makes the code worse and harder to understand instead of better I have fully 'flattened' the code.
  • As good as possible eliminated exactly the same code repeating again and again
  • Have put things which belong together near to each other in code
  • Added the possibility to pause/restart the game by pressing the "space" button.
  • Set up the threshold for detecting collisions, so crashes of players are now detected
  • Set the width and height values to a half, so that collisions at screen edges are now detected
  • Considering that in Python you can write good looking and intuitive min < x < max instead of min < x and x < max I decided to use it in detecting collisions, but not as a check if the player is outside of the screen area (because the expression max < x < min doesn't work) but if he is within. If the player is no more within, there is a collision.
  • Another shortcut in collision detection is to use the .distance() function for detecting collision between the player turtles instead of evaluation of their coordinates.
  • Added collision detection for the trace the player turtles leave on the screen so that now running into the path of the other player is detected.
  • Added the possibility to pause and restart the game by pressing "space'. Not restarted game will exit and close the window.

What could be further done to this code in order to improve it even more? The most urgent improvement would be to speed up the code in the collision detection part by replacing cloning of the turtles by another way of storing the turtle path and another way of detecting collision with the path.

Below the background image the after the image following code will try to load from the same directory from which the code is running:

Game background image

import time, turtle
S_WIDTH, S_HEIGHT   = 1280, 850 # size of created Screen (window) 
PLAYER_MIN_DISTANCE = 15.0      # for collision between players
X_MIN, X_MAX = -S_WIDTH/2, S_WIDTH/2 # for collision of players with ... 
Y_MIN, Y_MAX = -S_HEIGHT/2, S_HEIGHT/2 # ... sides of the screen

# For displaying of messages to the user about game status (win/loss): 
message_turtle = turtle.Turtle(visible=False)
message_turtle.color("white")

red_clones  = []
blue_clones = []
CLONE_DIST  = PLAYER_MIN_DISTANCE/1.1
def check_collisions():
    global red_clones, blue_clones, game_running
    msg = "" # msg as not empty string will indicate collision

    if not any( blue_player.distance(blue_clone) < CLONE_DIST for blue_clone in  blue_clones):
        bpc = blue_player.clone(); bpc.hideturtle(); blue_clones.append( bpc )
    if not any( red_player.distance( red_clone ) < CLONE_DIST for red_clone  in  red_clones):
        rpc = red_player.clone();  rpc.hideturtle();  red_clones.append( rpc )

    for red_clone in red_clones: 
        if blue_player.distance(red_clone) < PLAYER_MIN_DISTANCE:
            msg = "Blue crashed in Red's path.\nRed wins!"
    for blue_clone in blue_clones:
        if red_player.distance(blue_clone) < PLAYER_MIN_DISTANCE:
            msg = "Red crashed in Blue's path.\nBlue wins!"
            
    if( blue_player.distance(red_player) < PLAYER_MIN_DISTANCE ): 
        msg = "Red and Blue Crashed!\nGame over!"

    if not ( X_MIN < blue_player.xcor() < X_MAX and Y_MIN < blue_player.ycor() < Y_MAX ):
        msg = "Blue went out of bounds.\nRed wins!"
    if not ( X_MIN < red_player.xcor() < X_MAX and Y_MIN < red_player.ycor() < Y_MAX ):
        msg = "Red went out of bounds.\nBlue wins!"

    if msg: 
        message_turtle.write( msg, font=('Arial', 25, 'italic'), align='center')
        pause_game()
        game_running = False
        del red_clones[:] ; del blue_clones[:]
        time.sleep(5)
        message_turtle.undo()
        blue_player.clear(); red_player.clear() 
        blue_player.is_moving=False; red_player.is_moving=False
        blue_player.pu();blue_player.goto(-1*S_WIDTH/3, S_HEIGHT/8);blue_player.pd()
        red_player.pu() ; red_player.goto(   S_WIDTH/3, S_HEIGHT/8); red_player.pd()
        blue_player.setheading(  0); red_player.setheading(180)
        message_turtle.write( "Press SPACE for a NEW GAME", font=('Arial', 25, 'italic'), align='center')
        countdown()
        if not game_paused:
            message_turtle.undo()
            game_running = True
        else: 
            screen.bye()
        
# Setting up the display area and making shapes available for later use 
screen = turtle.Screen()
screen.setup(S_WIDTH, S_HEIGHT)
# 
screen.bgpic(    'TronBg.png'  )
screen.bgcolor(  'green'       )
# screen.addshape( 'BlueBike.gif')
# screen.addshape( 'RedBike.gif' )

# Create the Blue Player Turtle and its controls 
blue_player = turtle.Turtle("turtle")
blue_player.shapesize(stretch_wid=3, stretch_len=3)
blue_player.setheading(  0)
# blue_player.shape('BlueBike.gif')
blue_player.pencolor("blue")
blue_player.pensize(15)
blue_player.pu()
blue_player.goto(-1*S_WIDTH/3, S_HEIGHT/8)
blue_player.pd()
blue_player.is_moving = False
def blue_up()   : blue_player.setheading( 90);blue_player.is_moving=True
def blue_down() : blue_player.setheading(270);blue_player.is_moving=True
def blue_left() : blue_player.setheading(180);blue_player.is_moving=True
def blue_right(): blue_player.setheading(  0);blue_player.is_moving=True
screen.onkey(blue_up,       "Up")
screen.onkey(blue_down,   "Down")
screen.onkey(blue_left,   "Left")
screen.onkey(blue_right, "Right")

# Create the Red Player Turtle and its controls 
red_player = turtle.Turtle("turtle")
red_player.shapesize(stretch_wid=3, stretch_len=3)
red_player.setheading(180)
# red_player.shape('RedBike.gif')
red_player.pencolor("red")
red_player.pensize(15)
red_player.pu()
red_player.goto(S_WIDTH/3, S_HEIGHT/8)
red_player.pd()
red_player.is_moving = False
def red_up()    : red_player.setheading( 90); red_player.is_moving=True
def red_down()  : red_player.setheading(270); red_player.is_moving=True
def red_left()  : red_player.setheading(180); red_player.is_moving=True
def red_right() : red_player.setheading(  0); red_player.is_moving=True
screen.onkey(red_up,         "w")
screen.onkey(red_down,       "s")
screen.onkey(red_left,       "a")
screen.onkey(red_right,      "d")

# Allow pausing the game by pressing space
game_paused = False
def pause_game():
    global game_paused
    if game_paused: game_paused = False
    else:           game_paused = True
screen.onkey(pause_game, "space")

# Countdown: 
countdown_turtle = turtle.Turtle(visible=False)
countdown_turtle.color("white")
countdown_turtle.goto(0, -50)
def countdown(): 
    for i in range(3,-1,-1):
        countdown_turtle.write(i, font=('Arial', 25, 'italic'), align='center') 
        time.sleep(1)
        countdown_turtle.undo()
countdown()

# Establishing a screen.ontimer() loop driving the turtles movement
game_running = True
def gameloop():
    if not game_paused and game_running:
        if blue_player.is_moving: blue_player.forward(3)
        if  red_player.is_moving:  red_player.forward(3)
        check_collisions()
    screen.ontimer(gameloop, 30) # 10ms (0.01s) (1000ms/10ms = 100 FPS)
gameloop()

# Start processing of key-presses
screen.listen()
screen.mainloop()
我的痛♀有谁懂 2025-02-16 02:16:59

首先,您应该在gameloop()函数中调用collionis(),以便每次碰撞玩家移动时检查碰撞。执行此操作后,将从函数中删除。另外,如果有碰撞以结束游戏,请返回true

def gameloop():
    move_player(red_player, red_direction)
    move_player(blue_player, blue_direction)
    # Check for a collision. End game if there is one
    if collisions(): return
    #Repeat after 10ms (0.01s) (1000ms/10ms = 100 FPS)
    screen.ontimer(gameloop, 10)

# Helper function to print end of game message
def game_over(message):
    TurtleCrash = turtle.Turtle(visible=False)
    TurtleCrash.color("white")
    style = ('Arial', 25, 'italic')
    TurtleCrash.write(f"{message}\nGame over!", font=style, align='center')

left = -(width // 2)
right = -left
bottom = -(height // 2)
top = -bottom
def collisions():
    if math.isclose(blue_player.xcor(), red_player.xcor(), abs_tol=1e-10) and math.isclose(blue_player.ycor(), red_player.ycor(), abs_tol=1e-10):
        game_over("Red and Blue Crashed!")
        return True
         
    if blue_player.xcor() > right or blue_player.xcor() < left:
        game_over("Blue went out of bounds.\nRed wins!")
        return True
        
    if blue_player.ycor() > top or blue_player.ycor() < bottom:
        game_over("Blue went out of bounds.\nRed wins!")
       return True
  
    if red_player.xcor() > right or red_player.xcor() < left:
        game_over("Red went out of bounds.\nBlue wins!")
        return True
  
    if red_player.ycor() > top or red_player.ycor() < bottom:
        game_over("Red went out of bounds.\nBlue wins!")
        return True
     
    return False

至于与一条线相交,我的最初建议是在乌龟移动到的位置上阅读像素,如果不是黑色,则会发生碰撞。不幸的是,据我所知,没有简单的方法可以阅读带有Turtle的像素。因此,您需要保留玩家访问的所有职位的列表并使用。或者也许使用了更先进的引擎,例如Pygame。

有很多改进代码的地方。如果您想获得一些反馈,请在

First, you should call collisions() in the gameloop() function so it checks for a collision each time the players move. After doing this, remove the while from the function. Also, have the function return True if there is a collision to end the game.

def gameloop():
    move_player(red_player, red_direction)
    move_player(blue_player, blue_direction)
    # Check for a collision. End game if there is one
    if collisions(): return
    #Repeat after 10ms (0.01s) (1000ms/10ms = 100 FPS)
    screen.ontimer(gameloop, 10)

# Helper function to print end of game message
def game_over(message):
    TurtleCrash = turtle.Turtle(visible=False)
    TurtleCrash.color("white")
    style = ('Arial', 25, 'italic')
    TurtleCrash.write(f"{message}\nGame over!", font=style, align='center')

left = -(width // 2)
right = -left
bottom = -(height // 2)
top = -bottom
def collisions():
    if math.isclose(blue_player.xcor(), red_player.xcor(), abs_tol=1e-10) and math.isclose(blue_player.ycor(), red_player.ycor(), abs_tol=1e-10):
        game_over("Red and Blue Crashed!")
        return True
         
    if blue_player.xcor() > right or blue_player.xcor() < left:
        game_over("Blue went out of bounds.\nRed wins!")
        return True
        
    if blue_player.ycor() > top or blue_player.ycor() < bottom:
        game_over("Blue went out of bounds.\nRed wins!")
       return True
  
    if red_player.xcor() > right or red_player.xcor() < left:
        game_over("Red went out of bounds.\nBlue wins!")
        return True
  
    if red_player.ycor() > top or red_player.ycor() < bottom:
        game_over("Red went out of bounds.\nBlue wins!")
        return True
     
    return False

As far as intersecting with a line, my initial suggestion would be to read the pixel at the position the turtle is moving to and if it is not black, then there is a collision. Unfortunately, as far as I can see, there's no easy way to read a pixel with Turtle. So you need to keep a list of all the positions a player has visited and use that. Or maybe used a more advanced engine like PyGame.

There are lots of places to improve the code. If you want to get some feedback, post the code over at https://codereview.stackexchange.com/.

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