initial attempt at sprite-based drawing
This commit is contained in:
parent
a540b96c75
commit
22818f983d
|
@ -38,6 +38,62 @@
|
||||||
<Architecture>X86</Architecture>
|
<Architecture>X86</Architecture>
|
||||||
</Interpreter>
|
</Interpreter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Assets\" />
|
||||||
|
<Folder Include="Assets\Sphere\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Assets\Sphere\0001.png" />
|
||||||
|
<Content Include="Assets\Sphere\0002.png" />
|
||||||
|
<Content Include="Assets\Sphere\0003.png" />
|
||||||
|
<Content Include="Assets\Sphere\0004.png" />
|
||||||
|
<Content Include="Assets\Sphere\0005.png" />
|
||||||
|
<Content Include="Assets\Sphere\0006.png" />
|
||||||
|
<Content Include="Assets\Sphere\0007.png" />
|
||||||
|
<Content Include="Assets\Sphere\0008.png" />
|
||||||
|
<Content Include="Assets\Sphere\0009.png" />
|
||||||
|
<Content Include="Assets\Sphere\0010.png" />
|
||||||
|
<Content Include="Assets\Sphere\0011.png" />
|
||||||
|
<Content Include="Assets\Sphere\0012.png" />
|
||||||
|
<Content Include="Assets\Sphere\0013.png" />
|
||||||
|
<Content Include="Assets\Sphere\0014.png" />
|
||||||
|
<Content Include="Assets\Sphere\0015.png" />
|
||||||
|
<Content Include="Assets\Sphere\0016.png" />
|
||||||
|
<Content Include="Assets\Sphere\0017.png" />
|
||||||
|
<Content Include="Assets\Sphere\0018.png" />
|
||||||
|
<Content Include="Assets\Sphere\0019.png" />
|
||||||
|
<Content Include="Assets\Sphere\0020.png" />
|
||||||
|
<Content Include="Assets\Sphere\0021.png" />
|
||||||
|
<Content Include="Assets\Sphere\0022.png" />
|
||||||
|
<Content Include="Assets\Sphere\0023.png" />
|
||||||
|
<Content Include="Assets\Sphere\0024.png" />
|
||||||
|
<Content Include="Assets\Sphere\0025.png" />
|
||||||
|
<Content Include="Assets\Sphere\0026.png" />
|
||||||
|
<Content Include="Assets\Sphere\0027.png" />
|
||||||
|
<Content Include="Assets\Sphere\0028.png" />
|
||||||
|
<Content Include="Assets\Sphere\0029.png" />
|
||||||
|
<Content Include="Assets\Sphere\0030.png" />
|
||||||
|
<Content Include="Assets\Sphere\0031.png" />
|
||||||
|
<Content Include="Assets\Sphere\0032.png" />
|
||||||
|
<Content Include="Assets\Sphere\0033.png" />
|
||||||
|
<Content Include="Assets\Sphere\0034.png" />
|
||||||
|
<Content Include="Assets\Sphere\0035.png" />
|
||||||
|
<Content Include="Assets\Sphere\0036.png" />
|
||||||
|
<Content Include="Assets\Sphere\0037.png" />
|
||||||
|
<Content Include="Assets\Sphere\0038.png" />
|
||||||
|
<Content Include="Assets\Sphere\0039.png" />
|
||||||
|
<Content Include="Assets\Sphere\0040.png" />
|
||||||
|
<Content Include="Assets\Sphere\0041.png" />
|
||||||
|
<Content Include="Assets\Sphere\0042.png" />
|
||||||
|
<Content Include="Assets\Sphere\0043.png" />
|
||||||
|
<Content Include="Assets\Sphere\0044.png" />
|
||||||
|
<Content Include="Assets\Sphere\0045.png" />
|
||||||
|
<Content Include="Assets\Sphere\0046.png" />
|
||||||
|
<Content Include="Assets\Sphere\0047.png" />
|
||||||
|
<Content Include="Assets\Sphere\0048.png" />
|
||||||
|
<Content Include="Assets\Sphere\0049.png" />
|
||||||
|
<Content Include="Assets\Sphere\0050.png" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" />
|
||||||
<!-- Uncomment the CoreCompile target to enable the Build command in
|
<!-- Uncomment the CoreCompile target to enable the Build command in
|
||||||
Visual Studio and specify your pre- and post-build commands in
|
Visual Studio and specify your pre- and post-build commands in
|
||||||
|
|
19
OrbitSim.py
19
OrbitSim.py
|
@ -44,7 +44,7 @@ class Planet:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.mass = mass
|
self.mass = mass
|
||||||
self.radius = radius
|
self.radius = radius
|
||||||
self.rotationPercentage = 0.04
|
self.rotationPercentage = 0.00
|
||||||
self.rotationPeriod = rotationPeriod
|
self.rotationPeriod = rotationPeriod
|
||||||
|
|
||||||
def rotate(self, timeDelta:"Seconds"):
|
def rotate(self, timeDelta:"Seconds"):
|
||||||
|
@ -85,6 +85,8 @@ def physicsUpdate(objects, orbitlines, deltaTime):
|
||||||
accel = Point.scalarMult(Point.subtract(obj.location, obj.parentPlanet.location).normalize(),-(config()["G"] * obj.parentPlanet.mass)/(Point.subtract(obj.location, obj.parentPlanet.location).magnitude() ** 2))
|
accel = Point.scalarMult(Point.subtract(obj.location, obj.parentPlanet.location).normalize(),-(config()["G"] * obj.parentPlanet.mass)/(Point.subtract(obj.location, obj.parentPlanet.location).magnitude() ** 2))
|
||||||
obj.velocity = Point.add(obj.velocity, Point.scalarMult(accel, deltaTime))
|
obj.velocity = Point.add(obj.velocity, Point.scalarMult(accel, deltaTime))
|
||||||
obj.location = Point.add(obj.location, Point.scalarMult(obj.velocity, deltaTime))
|
obj.location = Point.add(obj.location, Point.scalarMult(obj.velocity, deltaTime))
|
||||||
|
elif type(obj).__name__ == "Planet":
|
||||||
|
obj.rotate(deltaTime)
|
||||||
for line in orbitlines:
|
for line in orbitlines:
|
||||||
line.update()
|
line.update()
|
||||||
|
|
||||||
|
@ -101,7 +103,7 @@ if __name__=="__main__":
|
||||||
running = True
|
running = True
|
||||||
display = False
|
display = False
|
||||||
thisEarth = deepcopy(Planet.Earth)
|
thisEarth = deepcopy(Planet.Earth)
|
||||||
sat = OrbitingBody(Point(config()["earthRadius"] * 1.5, 0, 0), Point(2000,6000,-2500), "BoSLOO", 3, thisEarth)
|
sat = OrbitingBody(Point(config()["earthRadius"] * 2, 0, 0), Point(0,0,0), "BoSLOO", 3, thisEarth)
|
||||||
orbitlines = []
|
orbitlines = []
|
||||||
renderObjects = [thisEarth, sat, orbitlines]
|
renderObjects = [thisEarth, sat, orbitlines]
|
||||||
imageThread = threading.Thread()
|
imageThread = threading.Thread()
|
||||||
|
@ -114,16 +116,15 @@ if __name__=="__main__":
|
||||||
elif event.type == pygame.MOUSEBUTTONDOWN:
|
elif event.type == pygame.MOUSEBUTTONDOWN:
|
||||||
if not display:
|
if not display:
|
||||||
display = True
|
display = True
|
||||||
camera = Camera(window, Point(0, 0, 4 * config()["earthRadius"]), thisEarth, renderObjects)
|
camera = Camera(window, Point(0, 0, 2 * config()["earthRadius"]), thisEarth, renderObjects)
|
||||||
pygame.draw.circle(window, (255,255,255), pygame.mouse.get_pos(), 100)
|
|
||||||
camera.renderFrame()
|
camera.renderFrame()
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
else:
|
else:
|
||||||
if not imageThread.is_alive():
|
#if not imageThread.is_alive():
|
||||||
imageThread = threading.Thread(target=camera.renderImage, args=(sat, thisEarth, orbitlines))
|
#imageThread = threading.Thread(target=camera.renderImage, args=(sat, thisEarth, orbitlines))
|
||||||
imageThread.start()
|
#imageThread.start()
|
||||||
display = False
|
#display = False
|
||||||
window.fill((0,0,0))
|
#window.fill((0,0,0))
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
if display:
|
if display:
|
||||||
deltaTime = frameTime * config()["timeScale"]
|
deltaTime = frameTime * config()["timeScale"]
|
||||||
|
|
67
renderer.py
67
renderer.py
|
@ -1,6 +1,10 @@
|
||||||
import numpy, pygame, math
|
import numpy, pygame, math, os
|
||||||
import pygame.freetype
|
import pygame.freetype
|
||||||
|
|
||||||
|
ASSET_DIR = "Assets"
|
||||||
|
SPHERE_FOLDER_NAME = "Sphere"
|
||||||
|
|
||||||
|
|
||||||
class Point:
|
class Point:
|
||||||
"""Numpy 3-vec"""
|
"""Numpy 3-vec"""
|
||||||
def __init__(self, x, y, z):
|
def __init__(self, x, y, z):
|
||||||
|
@ -70,15 +74,52 @@ class Plane:
|
||||||
self.point = point
|
self.point = point
|
||||||
self.normal = normal
|
self.normal = normal
|
||||||
|
|
||||||
|
class PlanetSprite(pygame.sprite.Sprite):
|
||||||
|
def __init__(self, camera, parentPlanet:"Planet"):
|
||||||
|
pygame.sprite.Sprite.__init__(self)
|
||||||
|
#the rotation animation loops every 64th of a rotation, so determine and store the frame number.
|
||||||
|
self.frames = {}
|
||||||
|
for imgName in os.listdir(os.path.join(ASSET_DIR, SPHERE_FOLDER_NAME)):
|
||||||
|
if imgName.endswith(".png"):
|
||||||
|
self.frames[imgName.strip(".png")] = pygame.image.load(os.path.join(ASSET_DIR, SPHERE_FOLDER_NAME, imgName)).convert_alpha()
|
||||||
|
self.parentPlanet = parentPlanet
|
||||||
|
self.frameNumber = str(round(math.modf(self.parentPlanet.rotationPercentage * 64)[0] * 49) + 1).zfill(4)
|
||||||
|
self.image = self.frames[self.frameNumber]
|
||||||
|
self.setSize(camera)
|
||||||
|
|
||||||
|
|
||||||
|
def setSize(self, camera):
|
||||||
|
winWidth, winHeight = camera.surface.get_size()
|
||||||
|
distance = Point.subtract(camera.location, self.parentPlanet.location).magnitude()
|
||||||
|
widthHalf = self.parentPlanet.radius
|
||||||
|
angle = numpy.arctan(widthHalf/distance) #the angle from center to edge of the sphere, from the camera
|
||||||
|
sizeAsPercent = numpy.degrees(angle)/camera.hFOV
|
||||||
|
self.sideLength = int(winWidth*sizeAsPercent)
|
||||||
|
self.image = pygame.transform.scale(self.image, (self.sideLength, self.sideLength))
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.rect.center = (winWidth/2, winHeight/2)
|
||||||
|
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.frameNumber = str(round(math.modf(self.parentPlanet.rotationPercentage * 64)[0] * 49) + 1).zfill(4)
|
||||||
|
self.image = pygame.image.load(os.path.join(ASSET_DIR, SPHERE_FOLDER_NAME, f"{self.frameNumber}.png")).convert_alpha()
|
||||||
|
if self.sideLength is not None:
|
||||||
|
self.image = pygame.transform.scale(self.image, (self.sideLength, self.sideLength))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Camera:
|
class Camera:
|
||||||
"""Object which will be used to paint pixels on screen."""
|
"""Object which will be used to paint pixels on screen."""
|
||||||
def __init__(self, surface:pygame.Surface, location:Point, target:"Planet", objects, hFOV = 55, vFOV = 55):
|
def __init__(self, surface:pygame.Surface, location:Point, target:"Planet", objects, hFOV = 60, vFOV = 60):
|
||||||
self.surface = surface
|
self.surface = surface
|
||||||
self.objects = objects
|
self.objects = objects
|
||||||
self.location = location
|
self.location = location
|
||||||
self.target = target
|
self.target = target
|
||||||
self.hFOV = hFOV
|
self.hFOV = hFOV
|
||||||
self.vFOV = vFOV
|
self.vFOV = vFOV
|
||||||
|
self.spriteGroup = pygame.sprite.Group()
|
||||||
|
self.spriteGroup.add(PlanetSprite(self, self.target))
|
||||||
|
|
||||||
|
|
||||||
def isInside(self, planet:"Planet"):
|
def isInside(self, planet:"Planet"):
|
||||||
"""returns True if camera is inside the planet."""
|
"""returns True if camera is inside the planet."""
|
||||||
|
@ -93,6 +134,10 @@ class Camera:
|
||||||
vecToCenter.normalize()
|
vecToCenter.normalize()
|
||||||
screenPlane = Plane(Point.add(self.location, Point.scalarMult(vecToCenter, winDistance)), vecToCenter)
|
screenPlane = Plane(Point.add(self.location, Point.scalarMult(vecToCenter, winDistance)), vecToCenter)
|
||||||
screenSurface = pygame.Surface((winWidth, winHeight))
|
screenSurface = pygame.Surface((winWidth, winHeight))
|
||||||
|
screenSurface.fill((10,10,10))
|
||||||
|
|
||||||
|
self.spriteGroup.update()
|
||||||
|
self.spriteGroup.draw(screenSurface)
|
||||||
#pygame uses 0,0 as the top left corner
|
#pygame uses 0,0 as the top left corner
|
||||||
for obj in self.objects:
|
for obj in self.objects:
|
||||||
if type(obj).__name__ == "OrbitingBody":
|
if type(obj).__name__ == "OrbitingBody":
|
||||||
|
@ -102,13 +147,7 @@ class Camera:
|
||||||
if intersectPoint is not None:
|
if intersectPoint is not None:
|
||||||
intersectPoint = Point.add(intersectPoint, Point(int(winWidth/2), int(winHeight/2), 0))
|
intersectPoint = Point.add(intersectPoint, Point(int(winWidth/2), int(winHeight/2), 0))
|
||||||
pygame.draw.circle(screenSurface, (255,255,150), (int(intersectPoint.vector[0]), int(intersectPoint.vector[1])), obj.displaySize)
|
pygame.draw.circle(screenSurface, (255,255,150), (int(intersectPoint.vector[0]), int(intersectPoint.vector[1])), obj.displaySize)
|
||||||
elif type(obj).__name__ == "Planet":
|
|
||||||
target = obj
|
|
||||||
lineToCamera = Line(obj.location, self.location)
|
|
||||||
intersectPoint = lineToCamera.intersectWithPlane(screenPlane)
|
|
||||||
if intersectPoint is not None:
|
|
||||||
intersectPoint = Point.add(intersectPoint, Point(int(winWidth/2), int(winHeight/2), 0))
|
|
||||||
pygame.draw.circle(screenSurface, (255,255,150), (int(intersectPoint.vector[0]), int(intersectPoint.vector[1])), 15)
|
|
||||||
elif isinstance(obj, list):
|
elif isinstance(obj, list):
|
||||||
for orbitline in obj:
|
for orbitline in obj:
|
||||||
if orbitline.color != (0,0,0):
|
if orbitline.color != (0,0,0):
|
||||||
|
@ -125,16 +164,22 @@ class Camera:
|
||||||
rho, theta, phi = sat.location.polar()
|
rho, theta, phi = sat.location.polar()
|
||||||
theta = math.degrees(theta)
|
theta = math.degrees(theta)
|
||||||
phi = math.degrees(phi)
|
phi = math.degrees(phi)
|
||||||
|
if rho < self.target.radius:
|
||||||
|
0 == 0
|
||||||
|
|
||||||
#textSurface, rect = font.render(f"Speed: {round(sat.velocity.magnitude())} m/s \nAltitude: {round(rho - target.radius)} m", False, (255,255,255))
|
#textSurface, rect = font.render(f"Speed: {round(sat.velocity.magnitude())} m/s \nAltitude: {round(rho - target.radius)} m", False, (255,255,255))
|
||||||
font.render_to(screenSurface, (0,0), f"Speed: {round(sat.velocity.magnitude())} m/s \nAltitude: {round(rho - target.radius)} m", (255,255,255))
|
font.render_to(screenSurface, (0,0), f"Speed: {round(sat.velocity.magnitude())} m/s", (255,255,255))
|
||||||
|
font.render_to(screenSurface, (0,20), f"Altitude: {round((rho - self.target.radius)/1000)} km", (255,255,255))
|
||||||
|
|
||||||
|
self.surface.fill((0,0,0))
|
||||||
self.surface.blit(screenSurface, (0,0))
|
self.surface.blit(screenSurface, (0,0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def renderImage(self, sat:"OrbitingBody", planet:"Planet", points):
|
def renderImage(self, sat:"OrbitingBody", planet:"Planet", points):
|
||||||
"""generates a single image and saves it to disk"""
|
"""generates a single image and saves it to disk"""
|
||||||
frozenSat = sat.location
|
frozenSat = sat.location
|
||||||
rotValue = math.modf(planet.rotationPercentage * 12)[0] * 3.14159 / 6 #get percentage of 1/12 of a revolution
|
rotValue = math.modf(planet.rotationPercentage)[0] * 3.14159 / 6 #get percentage of 1/12 of a revolution
|
||||||
winWidth, winHeight = self.surface.get_size()
|
winWidth, winHeight = self.surface.get_size()
|
||||||
winDistance = winWidth * numpy.cos(numpy.radians(self.hFOV)/2) / 2 #distance for a virtual screen to exist in-space to give the correct FOV
|
winDistance = winWidth * numpy.cos(numpy.radians(self.hFOV)/2) / 2 #distance for a virtual screen to exist in-space to give the correct FOV
|
||||||
vecToCenter = Point.subtract(self.target.location, self.location)
|
vecToCenter = Point.subtract(self.target.location, self.location)
|
||||||
|
|
Loading…
Reference in a new issue