【问题标题】:How can I add collisions to a list of objects (circles) in tkinter?如何将碰撞添加到 tkinter 中的对象(圆圈)列表中?
【发布时间】:2021-12-10 02:23:02
【问题描述】:
import time
from tkinter import *
import random

class SpaceField:
    def __init__(self):

        self.window = Tk()
        self.window.title("Asteriods")
        self.canvas = self.canvas_display() #creates canvas
        self.asteriods = self.asteriod_creation_seperation() #creates asteroids 
        self.active = True
        self.move_active()  #Moves asteroids 
        self.canvas.update()

    def asteriod_creation_seperation(self): #creation of multple asteriods
        asteriod_spacingx = random.randint(1,800)
        asteriod_spacingy = random.randint(1,800)
        asteriod_list = list() # could list([])
        for i in range(15):
            asteriod = self.canvas.create_oval( 30, 50 , 80 , 100 , tags="asteriod", width=2, outline="white")
            asteriod_list.append("asteriod")
            self.canvas.move(asteriod, asteriod_spacingx, asteriod_spacingy)
            asteriod_spacingx = random.randint(1,500)
            asteriod_spacingy = random.randint(1,500)
            print(asteriod_spacingy)
        return asteriod_list

小行星创造。创建小行星并给它们随机位置。

    def asteriod_update(self):  #asteriods movement method #MAin problem
            x12 = 1
            self.canvas.move("asteriod", 3, x12)
            pos = self.canvas.coords("asteriod")
            print(pos)
            if (pos)[2] > 500:
                x12 *= 5

我认为这是我需要添加碰撞检测的地方。我只是不知道如何组合圆圈和碰撞的列表。


    def move_active(self): #Basically a true loop
        if self.active:
            self.asteriod_update()
            self.window.after(40, self.move_active)

def canvas_display(self):  #canvas
    canvas = Canvas(self.window, width=500, height=400, background='black')
    canvas.pack(expand=True, fill="both")
    canvas.update()
    return canvas

画布显示没什么特别的


    def run(self):
        self.window.mainloop()

if __name__ == '__main__':
    SpaceF = SpaceField()
    SpaceF.run()

【问题讨论】:

  • 你想用什么来碰撞这些小行星(通常通过测量这些圆的中心之间的距离是否等于或小于它们的半径之和来检测圆碰撞)? x12 *= 5 也什么都不做,因为该变量是本地变量并且会被垃圾收集,或者你没有显示一些代码,顺便说一句,你应该提供一个 minimal reproducible example(这也是一件)
  • 我想将小行星与画布边界相撞。就像画布是 600 像素宽一样,我希望小行星在达到极限时反弹回来。抱歉,我是堆栈溢出的新手,谢谢,我会尝试的。 @Matiiss

标签: python list tkinter collision-detection tkinter-canvas


【解决方案1】:

Asteroids 是一款经典游戏,但您的代码中存在许多问题。主要是在初始化期间调用move_active。这会阻止代码完成其mainloop 初始化。

另外一个问题是asteroid_update这个方法基本上什么都没做,同样用tags控制所有小行星也没有用。

其他一切都很好,尽管您可能会考虑使用多边形。

这是生成弹跳对象程序的一种方法。我插入了描述所用方法的备注。

物体撞击边界时会改变速度和方向,因此它们的轨迹是随机的。

from tkinter import *
from random import randint as rnd

class SpaceField:
    def __init__(self):

        self.window = Tk()
        self.window.title("Asteriods")
        # Define canvas size and active flag
        self.wide, self.high, self.active = 500, 400, True
        self.canvas_display()
        self.asteriod_creation_seperation()

    def asteriod_creation_seperation(self):
        self.asteroids, self.speed = [], []
        size, radius = 50, 25
        for i in range(15):
            spacex = rnd(size, self.wide - size)
            spacey = rnd(size, self.high - size)
            self.asteroids.append( # Store oval item id
                self.canvas.create_oval(
                    spacex, spacey, spacex+size, spacey+size,
                    width=2, tags = "asteriod", outline = "white"))
            self.speed.append((rnd(1,4),rnd(1,4))) # Store random speed x, y

    def asteriod_update(self): # MAIN DRIVER: Work on ALL asteroids
        for i, a in enumerate(self.asteroids):
            xx, yy = self.speed[i] # get speed data
            x, y, w, h = self.canvas.coords(a)
            # check for boundary hit then change direction and speed
            if x < 0 or w > self.wide:
                xx = -xx * rnd(1, 4)
            if y < 0 or h > self.high:
                yy = -yy * rnd(1, 4)
            # Limit max and min speed then store it
            self.speed[i] = (max( -4, min( xx, 4)), max( -4, min( yy, 4 )))
            self.canvas.move(a, xx, yy) # update asteroid position

    def move_active(self):
        if self.active:
            self.asteriod_update()
            self.window.after(40, self.move_active)

    def canvas_display(self):
        self.canvas = Canvas(
            self.window, width = self.wide,
            height = self.high, background = "black")
        self.canvas.pack(expand = True, fill = "both")

    def run(self): # Begin asteroids here so that mainloop is executed
        self.window.after(200, self.move_active)
        self.window.mainloop()

if __name__ == "__main__":
    SpaceF = SpaceField()
    SpaceF.run()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 1970-01-01
    相关资源
    最近更新 更多