# -*- 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()
一碰撞就报错