如何限制按下按钮的次数

时间:2019-06-29 17:37:36

标签: python turtle-graphics

我正在尝试制作一个游戏,在其中您可以发射子弹杀死表情符号。但是,我无法弄清楚如何停止发送空格键来发射子弹。如果您继续发送垃圾邮件,那么游戏将变得非常简单。我不确定是否应该使用什么命令。请帮忙!谢谢!

这是我的代码:

# import everything from turtle
from turtle import *
import random
import math
#create a link to the object (creates the environment)
screen = Screen()
speed1 = 1.3
ht()
amountOfEmojis = 11
#set a boundary for screen, if touches end, goes to the other side
screenMinX = -screen.window_width()/2
screenMinY = -screen.window_height()/2
screenMaxX = screen.window_width()/2
screenMaxY = screen.window_height()/2
#establish important data for screen environment
screen.setworldcoordinates(screenMinX,screenMinY,screenMaxX,screenMaxY)
screen.bgcolor("black")
#turtle setup
penup()
ht()
speed(0)
goto(0, screenMaxY - 50)
color('white')
write("Welcome to Emoji Run!", align="center", font=("Courier New",26))
goto(0, screenMaxY - 70)
write("Use the arrow keys to move and space to fire. The point of the game is to kill the emojis", align="center")
goto(0, 0)
color("red")

emojis = ["Poop_Emoji_7b204f05-eec6-4496-91b1-351acc03d2c7_grande.png", "1200px-Noto_Emoji_KitKat_263a.svg.png", 
"annoyningface.png", "Emoji_Icon_-_Sunglasses_cool_emoji_large.png"]


class Bullet(Turtle):
  #constructor, object for a class, pass in information
  def __init__(self,screen,x,y,heading):
    #create a bullet
    Turtle.__init__(self)#clones bullet
    self.speed(0)
    self.penup()
    self.goto(x,y)
    self.seth(heading)#pointing to itself
    self.screen = screen 
    self.color('yellow')
    self.max_distance = 500
    self.distance = 0
    self.delta = 20
    self.shape("bullet")
  #logic to move bullet
  def move(self):
    self.distance = self.distance + self.delta#how fast it's going to move
    self.forward(self.delta)
    if self.done():
      self.reset()

  def getRadius(self):
    return 4#collision detection helper function

  def blowUp(self):
    self.goto(-300,0)#function that makes something go off the screen 

  def done(self):
    return self.distance >= self.max_distance # append to list

class Asteroid(Turtle):
  def __init__(self,screen,dx,dy,x,y,size,emoji):#spawn asteroid randomly
    Turtle.__init__(self)#clone itself
    self.speed(0)
    self.penup()
    self.goto(x,y)
    self.color('lightgrey')
    self.size = size
    self.screen = screen
    self.dx = dx
    self.dy = dy
    r = random.randint(0, len(emoji) - 1)
    screen.addshape(emojis[r])
    self.shape(emojis[r])
    #self.shape("rock" + str(size)) #sets size and shape for asteroid

  def getSize(self):#part of collision detection
    return self.size
  #getter and setter functions
  def getDX(self):
    return self.dx

  def getDY(self):
    return self.dy

  def setDX(self,dx):
    self.dx = dx

  def setDY(self,dy):
    self.dy = dy

  def move(self):
    x = self.xcor()
    y = self.ycor()
#if on edge of screen. go to opposite side
    x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
    y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY

    self.goto(x,y)

  def blowUp(self):
    self.goto(-300,0)#function that makes something go off the screen 

  def getRadius(self):
    return self.size * 10 - 5

class SpaceShip(Turtle):
  def __init__(self,screen,dx,dy,x,y):
    Turtle.__init__(self)
    self.speed(0)
    self.penup()
    self.color("white")
    self.goto(x,y)
    self.dx = dx
    self.dy = dy
    self.screen = screen   
    self.bullets = []
    self.shape("turtle")

  def move(self):
    x = self.xcor()
    y = self.ycor()
    x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
    y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY

    self.goto(x,y)
  #logic for collision
  def powPow(self, asteroids):
    dasBullets = []
    for bullet in self.bullets:
      bullet.move()
      hit = False
      for asteroid in asteroids:
        if intersect(asteroid, bullet):#counts every asteroid to see if it hits
          asteroids.remove(asteroid)
          asteroid.blowUp()
          bullet.blowUp()
          hit = True
      if (not bullet.done() and not hit):
        dasBullets.append(bullet)


    self.bullets = dasBullets

  def fireBullet(self):
    self.bullets.append(Bullet(self.screen, self.xcor(), self.ycor(), self.heading()))

  def fireEngine(self):#how turtle moves
    angle = self.heading()
    x = math.cos(math.radians(angle))
    y = math.sin(math.radians(angle))

    self.dx = self.dx + x#how it rotates
    self.dy = self.dy + y
    self.dx = self.dx / speed1
    self.dy = self.dy / speed1

  #extra function
  def turnTowards(self,x,y):
    if x < self.xcor():
      self.left(7)
    if x > self.xcor():
      self.right(7)

  def getRadius(self):
      return 10

  def getDX(self):
      return self.dx

  def getDY(self):
      return self.dy

#collision detection
def intersect(object1,object2):
  dist = math.sqrt((object1.xcor() - object2.xcor())**2 + (object1.ycor() - object2.ycor())**2)

  radius1 = object1.getRadius()
  radius2 = object2.getRadius()

  # The following if statement could be written as 
  # return dist <= radius1+radius2
  if dist <= radius1+radius2:
      return True
  else:
      return False

#adds object to screen
screen.register_shape("rock3",((-20, -16),(-21, 0), (-20,18),(0,27),(17,15),(25,0),(16,-15),(0,-21)))
screen.register_shape("rock2",((-15, -10),(-16, 0), (-13,12),(0,19),(12,10),(20,0),(12,-10),(0,-13)))
screen.register_shape("rock1",((-10,-5),(-12,0),(-8,8),(0,13),(8,6),(14,0),(12,0),(8,-6),(0,-7)))
screen.register_shape("ship",((-10,-10),(0,-5),(10,-10),(0,10)))
screen.register_shape("bullet",((-2,-4),(-2,4),(2,4),(2,-4)))
#ship spawn exactly the middle everytime
ship = SpaceShip(screen,0,0,(screenMaxX-screenMinX)/2+screenMinX,(screenMaxY-screenMinY)/2 + screenMinY)

#randomize where they spawn
asteroids = []
for k in range(amountOfEmojis):
  dx = random.random() * 6 - 3
  dy = random.random() * 6 - 3
  x = random.randrange(10) * (screenMaxX - screenMinX) + screenMinX
  y = random.random() * (screenMaxY - screenMinY) + screenMinY
  asteroid = Asteroid(screen,dx,dy,x,y,random.randint(1,3), emojis)
  asteroids.append(asteroid)

def play():
  # Tell all the elements of the game to move
  ship.move()

  gameover = False
  for asteroid in asteroids:
    r = random.randint(0, 1)
    if r == 1:
      asteroid.right(50)
    else:
      asteroid.left(20)
    asteroid.move()
    if intersect(ship,asteroid):
      write("You Got Killed :(",font=("Verdana",25),align="center")
      gameover = True

  ship.powPow(asteroids)

  screen.update()

  if not asteroids:
    color('green')
    write("You Killed the Emojis!!",font=("Arial",30),align="center")
    ht()

  if not gameover:
    screen.ontimer(play, 30)

bullets = []
#controls
def turnLeft():
  ship.left(7)

def turnRight():
  ship.right(7)

def go():
  ship.fireEngine()

def fire():         
  ship.fireBullet()

ht()

screen.tracer(0);

screen.onkey(turnLeft, 'left')
screen.onkey(turnRight, 'right')
screen.onkey(go, 'up')
screen.onkey(fire, 'space')
screen.listen()

play()

2 个答案:

答案 0 :(得分:0)

您可以使用线程计时器防止每次单击按钮时调用该方法,并且只在SpaceShip类中提供两个属性。

每次调用方法fireBullet时,都会对变量can_shoot进行检查。如果是真的,则像您一样生成子弹,然后运行计时器(使用线程,以防止阻塞主流程),该计时器将can_shoot设置为False,休眠所需的毫秒数,然后将can_shoot设置为True,该方法可以再次调用。

import time
import threading

def __init__(self):
    # your stuff
    self.wait_between_fire = 300 / 1000  # amount of ms / 1000 to convert in seconds
    self.can_shoot = True

class TimerThread(threading.Thread):
    def __init__(self, ref):
        threading.Thread.__init__(self)
        self.ref = ref

    def run():
        self.ref.can_shoot = False
        time.sleep(ref.wait_between_fire)
        self.ref.can_shoot = True

def set_timer(self):
    TimerThread(self).start()

def fireBullet(self):
    if self.can_shoot:
        self.bullets.append(Bullet(self.screen, self.xcor(), self.ycor(), self.heading()))
        self.set_timer()

答案 1 :(得分:0)

我们不需要引入 time threading 即可解决此问题。我们可以使用乌龟自己的计时器事件来控制射速:

def fire():
    screen.onkey(None, 'space')
    ship.fireBullet()
    screen.ontimer(lambda: screen.onkey(fire, 'space'), 250)

在这里,我将射速限制为每秒4发。 (250/1000毫秒。)根据需要进行调整。下面是对程序进行的修改,包括此修改以及其他修复和样式调整:

from turtle import Screen, Turtle
from random import random, randint, randrange, choice
from math import radians, sin as sine, cos as cosine

class Bullet(Turtle):
    MAX_DISTANCE = 500
    DELTA = 20
    RADIUS = 4

    def __init__(self, position, heading):
        super().__init__(shape="bullet")

        self.hideturtle()
        self.penup()
        self.goto(position)
        self.setheading(heading)
        self.color('yellow')
        self.showturtle()

        self.distance = 0

    def move(self):
        self.distance += self.DELTA
        self.forward(self.DELTA)

        if self.done():
            self.reset()

    def getRadius(self):
        ''' collision detection helper method '''
        return self.RADIUS

    def blowUp(self):
        ''' method that makes something go off the screen '''
        self.hideturtle()

    def done(self):
        return self.distance >= self.MAX_DISTANCE

class Asteroid(Turtle):
    def __init__(self, dx, dy, position, size, emoji):
        super().__init__()

        self.hideturtle()
        self.penup()
        self.goto(position)
        self.color('lightgrey')

        emoji = choice(emojis)
        # screen.addshape(emoji)  # for StackOverflow debugging
        self.shape(emoji)
        self.showturtle()

        self.size = size
        self.dx = dx
        self.dy = dy

    def move(self):
        x, y = self.position()
        # if on edge of screen. go to opposite side
        x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
        y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY

        self.goto(x, y)

    def blowUp(self):
        ''' method that makes something go off the screen '''
        self.hideturtle()

    def getRadius(self):
        return self.size * 10 - 5

class SpaceShip(Turtle):
    RADIUS = 10

    def __init__(self, screen, dx, dy, x, y):
        super().__init__(shape='turtle')

        self.hideturtle()
        self.penup()
        self.color("white")
        self.goto(x, y)
        self.showturtle()

        self.dx = dx
        self.dy = dy
        self.screen = screen
        self.bullets = []

    def move(self):
        x, y = self.position()
        x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
        y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY

        self.goto(x, y)

    def powPow(self, asteroids):
        ''' logic for collision '''

        dasBullets = []

        for bullet in self.bullets:
            bullet.move()
            hit = False

            for asteroid in asteroids:
                if intersect(asteroid, bullet):  # counts every asteroid to see if it hits
                    asteroids.remove(asteroid)
                    asteroid.blowUp()
                    hit = True

            if not bullet.done() and not hit:
                dasBullets.append(bullet)
            else:
                bullet.blowUp()

        self.bullets = dasBullets

    def fireBullet(self):
        bullet = Bullet(self.position(), self.heading())

        self.bullets.append(bullet)

    def fireEngine(self):
        angle = self.heading()  # how turtle moves
        x = cosine(radians(angle))
        y = sine(radians(angle))

        self.dx = self.dx + x  # how it rotates
        self.dy = self.dy + y
        self.dx = self.dx / speed1
        self.dy = self.dy / speed1

    def getRadius(self):
        return self.RADIUS

    def turnLeft(self):
        self.left(7)

    def turnRight(self):
        self.right(7)

def intersect(object1, object2):
    ''' collision detection '''

    return object1.distance(object2) <= object1.getRadius() + object2.getRadius()

def play():
    # Tell all the elements of the game to move
    ship.move()

    gameover = False

    for asteroid in asteroids:
        r = randint(0, 1)
        if r == 1:
            asteroid.right(50)
        else:
            asteroid.left(20)
        asteroid.move()

        if intersect(ship, asteroid):
            turtle.write("You Got Killed :(", font=("Verdana", 25), align="center")
            gameover = True

    ship.powPow(asteroids)

    screen.update()

    if not asteroids:
        turtle.color('green')
        turtle.write("You Killed the Emojis!!", font=("Arial", 30), align="center")

    if not gameover:
        screen.ontimer(play, 30)

# controls
def fire():
    screen.onkey(None, 'space')
    ship.fireBullet()
    screen.ontimer(lambda: screen.onkey(fire, 'space'), 250)

# create a link to the object (creates the environment)
speed1 = 1.3
amountOfEmojis = 11

# establish important data for screen environment
screen = Screen()
screen.bgcolor("black")

# set a boundary for screen, if touches end, goes to the other side
screenMinX = -screen.window_width()/2
screenMinY = -screen.window_height()/2
screenMaxX = screen.window_width()/2
screenMaxY = screen.window_height()/2

screen.setworldcoordinates(screenMinX, screenMinY, screenMaxX, screenMaxY)

# adds object to screen
screen.register_shape("rock3", ((-20, -16), (-21, 0), (-20, 18), (0, 27), (17, 15), (25, 0), (16, -15), (0, -21)))
screen.register_shape("rock2", ((-15, -10), (-16, 0), (-13, 12), (0, 19), (12, 10), (20, 0), (12, -10), (0, -13)))
screen.register_shape("rock1", ((-10, -5), (-12, 0), (-8, 8), (0, 13), (8, 6), (14, 0), (12, 0), (8, -6), (0, -7)))
screen.register_shape("ship", ((-10, -10), (0, -5), (10, -10), (0, 10)))
screen.register_shape("bullet", ((-2, -4), (-2, 4), (2, 4), (2, -4)))

screen.tracer(0)

# turtle setup
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
turtle.goto(0, screenMaxY - 50)
turtle.color('white')
turtle.write("Welcome to Emoji Run!", align="center", font=("Courier New", 26))
turtle.goto(0, screenMaxY - 70)
turtle.write("Use the arrow keys to move, and space to fire. The point of the game is to kill the emojis.", align="center", font=("Courier New", 13))
turtle.goto(0, 0)
turtle.color("red")

emojis = [
    "Poop_Emoji_7b204f05-eec6-4496-91b1-351acc03d2c7_grande.png",
    "1200px-Noto_Emoji_KitKat_263a.svg.png",
    "annoyningface.png",
    "Emoji_Icon_-_Sunglasses_cool_emoji_large.png"
]

emojis = ['rock1', 'rock2', 'rock3']  # for StackOverflow debugging purposes

# ship spawn exactly the middle everytime
ship = SpaceShip(screen, 0, 0, (screenMaxX - screenMinX)/2 + screenMinX, (screenMaxY - screenMinY)/2 + screenMinY)

# randomize where they spawn
asteroids = []

for k in range(amountOfEmojis):
    dx, dy = random() * 6 - 3, random() * 6 - 3
    x = randrange(10) * (screenMaxX - screenMinX) + screenMinX
    y = random() * (screenMaxY - screenMinY) + screenMinY
    asteroid = Asteroid(dx, dy, (x, y), randint(1, 3), emojis)
    asteroids.append(asteroid)

screen.onkey(ship.turnLeft, 'Left')
screen.onkey(ship.turnRight, 'Right')
screen.onkey(ship.fireEngine, 'Up')
screen.onkey(fire, 'space')
screen.listen()

screen.update()

play()

screen.mainloop()

需要考虑的是,海龟是不会收集垃圾的全局实体。因此,您可能希望将用过的子弹收集在列表中以供重复使用,仅在需要时创建新子弹。