鱼C论坛

 找回密码
 立即注册
查看: 1777|回复: 1

[已解决]碰撞检测

[复制链接]
发表于 2023-2-12 11:40:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 歌者文明清理员 于 2023-2-12 11:43 编辑

源代码
只要看第 129 到 133 行就行了
# -*- coding: utf-8 -*-
import pygame
import math
import numpy as np
import random
from trail import TrailSprite
from tkinter import *

pygame.init()
G = 1
pygame.time.set_timer(pygame.USEREVENT, 5000)


class Star(pygame.sprite.Sprite, TrailSprite):
    def __init__(self, radius, mass, init_speed, pos):
        pygame.sprite.Sprite.__init__(self)
        self.radius = radius
        self.mass = mass
        self.color = rand_color()
        if init_speed:
            self.speed = init_speed
        self.image = pygame.Surface((radius * 2, radius * 2)).convert_alpha()
        self.image.fill((0, 0, 0, 0))
        pygame.draw.circle(self.image, self.color, (radius, radius), radius)
        TrailSprite.__init__(self, self.color, self.image, 1)
        TrailSprite.set_screen(self, screen)
        self.rect.center = pos

    def move(self):
        TrailSprite.update(self)
        self.rect.centerx += self.speed[0]
        self.rect.centery += self.speed[1]
        # 跑出窗口从另一边回来
        if self.rect.left <= 0 or self.rect.right >= width:
            self.rect.centerx %= width
            self.clear_trail()
        if self.rect.top <= 0 or self.rect.bottom >= height:
            self.rect.centery %= height
            self.clear_trail()


def all_clear_trail():
    for st in stars:
        st.clear_trail()


def rand_color():
    r = random.randint(0, 255)
    g = random.randint(0, 255)
    b = random.randint(0, 255)
    return r, g, b


def set_speed():
    global step
    if not entry.get().isdigit():
        return
    step = entry.get()
    root.destroy()


pygame.init()

size = width, height = 640, 480
bg = (0, 0, 0)

screen = pygame.display.set_mode(size)
pygame.display.set_caption("StarMotionSimulator")

stars = []  # 随机生成天体

clock = pygame.time.Clock()

step = 1
stop_moving = False
down = False
star_pos = (0, 0)
rel = [0, 0]
running = True
while running:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                stop_moving = not stop_moving
                all_clear_trail()
            elif event.key == pygame.K_r:
                stars.clear()
            elif event.key == pygame.K_s:
                root = Tk()
                root.title('SpeedEditor')
                root.geometry('100x50')
                label = Label(root, text='Speed')
                label.pack()
                entry = Entry(root)
                entry.pack()
                submit = Button(root, text='Confirm')
                submit['command'] = set_speed
                submit.pack()
                root.mainloop()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if not down:
                star_pos = event.pos
                down = True
        elif event.type == pygame.MOUSEBUTTONUP:
            down = False
            star = Star(5, 100, (-rel[0] // 4, -rel[1] // 4), event.pos)
            stars.append(star)
            rel.clear()
            rel.extend((0, 0))
        elif event.type == pygame.MOUSEMOTION:
            if down:  # 按下 + 移动 = 拖动
                rel[0] += event.rel[0]
                rel[1] += event.rel[1]
        elif event.type == pygame.USEREVENT:
            all_clear_trail()

    screen.fill((0, 0, 0))
    for star in stars:
        screen.blit(star.image, star.rect)
    if not stop_moving:
        for i in range(len(stars)):
            star = stars[i]
            for star2 in stars[(i + 1):]:
                distance = math.dist(star.rect.center, star2.rect.center)
                #### 从这里开始看
                if pygame.sprite.collide_circle(star, star2):
                    star.mass += star2.mass
                    stars.remove(star2)
                    continue
                #### 就是上面这段代码,一碰撞就报错
                if distance < 100:
                    distance = 100
                # 万有引力公式F=GMm/r**2,0.1是为了适当缩小万有引力,否则会出现天体一直在转圈,你可以自己调整数值
                f = (G * (star.mass * star2.mass)) / distance ** 2 * 0.1 * step
                relative_position = np.subtract(star.rect.center, star2.rect.center)
                angle = math.atan2(*relative_position[::-1])
                dx = math.cos(angle) * f
                dy = math.sin(angle) * f
                star.speed = np.subtract(star.speed, [dx, dy])
                star2.speed = np.add(star2.speed, [dx, dy])
            star.speed = [x for x in star.speed]  # 虽然天体是在做匀速直线运动,但不做衰减的话速度会一直叠加导致过快
            star.move()
    pygame.display.flip()
pygame.quit()
一碰撞就报错
IndexError: index out of range
链接放后面
感谢@鱼cpython学习者
最佳答案
2023-2-12 13:41:13
永远不要尝试一边迭代一个容器一边删除容器里面的东西,我吃过很多次亏
我的建议是把
stars.remove(star2)
换成
star2.mass = 0
destroyed.append(star2)
等到全部弄完再遍历destroyed,删除star
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-2-12 13:41:13 | 显示全部楼层    本楼为最佳答案   
永远不要尝试一边迭代一个容器一边删除容器里面的东西,我吃过很多次亏
我的建议是把
stars.remove(star2)
换成
star2.mass = 0
destroyed.append(star2)
等到全部弄完再遍历destroyed,删除star
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-14 20:57

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表