Maybe I have over-sold this program in this thread title. This program simulates a rocket-launch from Cape Canaveral to the Moon. But there are (as you will undoubtedly expect) very great simplifications.
The program uses _MAPTRIANGLE(3D) - I'm a real fan of this - to make a 3D world in which a rocket travels. And the rocket itself is a 3D object.
The motion of the rocket is determined by (approximations to) proper rocket mathematics. Pre-launch the rocket is filled with propellant which has two thirds of the total mass. At ignition, propellant pellets are ejected with high velocity to provide an upward thrust for the rocket. As the overall weight of the rocket decreases with time until the fuel is used up the acceleration of the rocket increases.
The rocket starts at Cape Canaveral and stands vertically. When the rocket is launched it travels upwards and directly forwards to eventually land at The Sea of Tranquillity on the Moon. The rocket has a constant force of gravity downwards - there is no travel in space with a reduction of gravity. So after the fuel is used up the rocket behaves as a ballistic object and describes a parabolic path.
The Cape Canaveral and Moon landscapes and the rocket and its fuel pellets are all 3D objects in the _MAPTRIANGLE(3D) space.
When the fuel pellets are being ejected, the display may look as if this is just a graphical effect. But as I said, there is real rocket physics going on at all stages of the flight.
There is some audio accompanying the display, and you may recognise an appropriate musical track. I recommend that you use ear-buds if possible to get the benefit of Richard Strauss's composition.
The first time that the program is run, the music track is played alone. Subsequent runs have the rocket launch sequence with Saturn-5 launch sounds - this drowns out the Strauss.
Unzip the file and place the folder in the QB64 folder:
Rocket MapTriangle.zip (Size: 4.04 MB / Downloads: 42)
The fun part of this program was getting the rocket mathematics working to a reasonable degree of faithfulness, bearing in mind the simplifications. The rocket starts vertically and needs some guidance to tilt it off the vertical to begin the travel forward. My first attempts started with the rocket already tilted forward and I quickly discovered that the rocket then immediately ploughs itself into the ground. Doubtless Werner von Braun discovered how to easily blow up the rocket on the launch pad when he was directing his V2 missiles at London.
In this program, at ignition individual propellant pellets are fired sequentially backwards. Just after ignition, the rocket is still too heavy for the thrust to move the rocket upward, but after a short period that thrust is sufficient to give lift-off and upward acceleration. When the speed of the rocket is sufficient there is a short period where the rocket is (manually) tilted forward slightly. Then the guided tilting is stopped and the rocket moves forward by thrust and gravity. The rocket is accelerated upwards and forwards. When the fuel is used up the rocket moves under gravity alone, continuing upwards with decreasing velocity and forwards with constant velocity. Eventually the rocket begins to fall back down and lands on the Moon. There is no soft landing which is more HG Wells rather than Apollo. BREAKING NEWS: Apparently some YouTube expert says that we never made it to the Moon. This program is an illusion.
The attached graphs show the progression of altitude, range (distance from launch site forwards out of the screen) and pitch (angle of the rocket from horizontal).
There were a number of compromises to be made in the program. In order to give a good display over the entire flight a large program window was required. A full 1080 HD window size would have been desirable but I restricted this so that most users can view the whole window. At maximum height the rocket is partly off-screen. The displayed rocket size is clearly way too large for the given flight, but even so the rocket and fuel pellets are rather small at Cape Canaveral.
If the window size is still too large to fit in your display I have made a window-capture video which you may wish to view - but the fun part is to look at the coding. NB The audio quality in the video is lower than if running the program.
I should apologise for the descent into whimsicality at the end of the program. It was an Irresistible Temptation.
When I discovered _MAPTRIANGLE(3D) I found it interesting. The fun is working out the appropriate mapping to go from a 2D image to a 3D image. Skilled QB64 programmers will use OpenGL but that has remained beyond me, and at present I seem to be in a _MAPTRIANGLE(3D) - Conic Sections coding phase. My two previous programs (https://qb64phoenix.com/forum/showthread.php?tid=4025, https://qb64phoenix.com/forum/showthread.php?tid=4052) had objects moving in hyperbolic paths and then in a 3D circular path. In this program I have an object moving along a parabolic path, and I'm investigating elliptical motion.
The program uses _MAPTRIANGLE(3D) - I'm a real fan of this - to make a 3D world in which a rocket travels. And the rocket itself is a 3D object.
The motion of the rocket is determined by (approximations to) proper rocket mathematics. Pre-launch the rocket is filled with propellant which has two thirds of the total mass. At ignition, propellant pellets are ejected with high velocity to provide an upward thrust for the rocket. As the overall weight of the rocket decreases with time until the fuel is used up the acceleration of the rocket increases.
The rocket starts at Cape Canaveral and stands vertically. When the rocket is launched it travels upwards and directly forwards to eventually land at The Sea of Tranquillity on the Moon. The rocket has a constant force of gravity downwards - there is no travel in space with a reduction of gravity. So after the fuel is used up the rocket behaves as a ballistic object and describes a parabolic path.
The Cape Canaveral and Moon landscapes and the rocket and its fuel pellets are all 3D objects in the _MAPTRIANGLE(3D) space.
When the fuel pellets are being ejected, the display may look as if this is just a graphical effect. But as I said, there is real rocket physics going on at all stages of the flight.
There is some audio accompanying the display, and you may recognise an appropriate musical track. I recommend that you use ear-buds if possible to get the benefit of Richard Strauss's composition.
The first time that the program is run, the music track is played alone. Subsequent runs have the rocket launch sequence with Saturn-5 launch sounds - this drowns out the Strauss.
Unzip the file and place the folder in the QB64 folder:
Rocket MapTriangle.zip (Size: 4.04 MB / Downloads: 42)
The fun part of this program was getting the rocket mathematics working to a reasonable degree of faithfulness, bearing in mind the simplifications. The rocket starts vertically and needs some guidance to tilt it off the vertical to begin the travel forward. My first attempts started with the rocket already tilted forward and I quickly discovered that the rocket then immediately ploughs itself into the ground. Doubtless Werner von Braun discovered how to easily blow up the rocket on the launch pad when he was directing his V2 missiles at London.
In this program, at ignition individual propellant pellets are fired sequentially backwards. Just after ignition, the rocket is still too heavy for the thrust to move the rocket upward, but after a short period that thrust is sufficient to give lift-off and upward acceleration. When the speed of the rocket is sufficient there is a short period where the rocket is (manually) tilted forward slightly. Then the guided tilting is stopped and the rocket moves forward by thrust and gravity. The rocket is accelerated upwards and forwards. When the fuel is used up the rocket moves under gravity alone, continuing upwards with decreasing velocity and forwards with constant velocity. Eventually the rocket begins to fall back down and lands on the Moon. There is no soft landing which is more HG Wells rather than Apollo. BREAKING NEWS: Apparently some YouTube expert says that we never made it to the Moon. This program is an illusion.
The attached graphs show the progression of altitude, range (distance from launch site forwards out of the screen) and pitch (angle of the rocket from horizontal).
There were a number of compromises to be made in the program. In order to give a good display over the entire flight a large program window was required. A full 1080 HD window size would have been desirable but I restricted this so that most users can view the whole window. At maximum height the rocket is partly off-screen. The displayed rocket size is clearly way too large for the given flight, but even so the rocket and fuel pellets are rather small at Cape Canaveral.
If the window size is still too large to fit in your display I have made a window-capture video which you may wish to view - but the fun part is to look at the coding. NB The audio quality in the video is lower than if running the program.
I should apologise for the descent into whimsicality at the end of the program. It was an Irresistible Temptation.
Code: (Select All)
'Rocket Launch, Travel & (Crash-)Land program by Magdha 30/10/25 QB64 v2.0
'Five stages of flight:
'1. Initial Vertical Thrust (craft too heavy) - Ignition
'2. Vertical Lift-off and acceleartion
'3. Guided Tilt
'4. Unguided Thrust
'5. Free flight under gravity (parabolic)
CONST False = 0, True = NOT False
CONST Sparks% = 5000, PreLaunch% = 1250, Ignition% = 200, FRatio! = 0.5, VSparks! = 1, deltaT! = 0.1
CONST ZOffset% = 1000, NoArcs%% = 64, Rad%% = 40, HalfLength%% = 150, NoseHeight%% = 50
CONST PelletSize%% = 5, LauchHeight% = 50, ArtificialDelay% = 40
CONST TranquilityBase% = -250, YDisp! = 0.85, ZDisp! = 7.2, LaunchPadZ% = -1500
DIM Pellets&(8), Fuel%%(Sparks%, 1), FuelStats!(Sparks%, 3) 'Each fuel pellet has (x,y,z), angle of thrust; propelled speed is constant
DIM MapFromCylinder%(NoArcs%%), MapToClinder!(NoArcs%%, 1), MapFromLogo%(8), MapToLogo!(8, 1)
DIM MapFromNoseCone%(NoArcs%%, 1), MapToNoseCone!(NoArcs%%, 3)
DIM SHARED Gamma!, Phi!, Z!, Y!, X!
IF _FILEEXISTS("Zarathustra.txt") THEN
DoBlast%% = True
ELSE
OPEN "Zarathustra.txt" FOR OUTPUT AS #1
PRINT #1, True
CLOSE #1
END IF
RANDOMIZE (TIMER)
_TITLE "Thus Spake Zarathustra"
Apollo11& = _LOADIMAGE("Armstrong-Collins-Aldrin.jpg", 33) 'Map this to rocket body
Canaveral& = _LOADIMAGE("Canaveral.jpg", 33)
Tranquility& = _LOADIMAGE("Tranquility A.jpg", 33)
ItsARocket& = _LOADIMAGE("Sputnik.jpg", 33)
Zarathustra& = _SNDOPEN("Also Sprach Zarathustra A.mp3")
Landed& = _SNDOPEN("The Eagle Has Landed.mp3")
GiantLeap& = _SNDOPEN("Giant Leap.mp3")
Blast& = _SNDOPEN("Blast.mp3")
'Rocket Body Image Map
ApolloI% = _WIDTH(Apollo11&) - 1
ApolloJ% = _HEIGHT(Apollo11&) - 1
FOR K%% = 0 TO NoArcs%%
MapFromCylinder%(K%%) = CINT(K%% * ApolloI% / NoArcs%%)
MapToClinder!(K%%, 0) = Rad%% * COS(2 * _PI * K%% / NoArcs%%) 'z
MapToClinder!(K%%, 1) = Rad%% * SIN(2 * _PI * K%% / NoArcs%%) 'x
NEXT K%%
SputnikWidth% = _WIDTH(ItsARocket&)
FOR K%% = -4 TO 4
MapFromLogo%(K%% + 4) = CINT((K%% + 4) * SputnikWidth% / 8)
MapToLogo!(K%% + 4, 0) = (Rad%% + 1) * COS(2 * _PI * K%% / NoArcs%%) 'z The +1 is needed otherwise logo not displayed
MapToLogo!(K%% + 4, 1) = (Rad%% + 1) * SIN(2 * _PI * K%% / NoArcs%%) 'x
NEXT K%%
'Nosecone Image
TempImage& = _NEWIMAGE(201, 201, 32)
_DEST TempImage&
COLOR _RGB32(255, 253, 208), _RGBA32(90, 0, 90, 0)
CLS
FOR I% = 0 TO 200
I1%% = I% - 100
FOR J% = 0 TO 200
J1%% = J% - 100
R! = SQR(I1%% * I1%% + J1%% * J1%%)
Th! = _ATAN2(J1%%, I1%%)
IF R! <= 101 THEN PSET (I%, J%), _RGB32(255 - 100 * (1 - 0.5 * SIN(Th!)) - 0.25 * R!, 253 - 100 * (1 - 0.5 * SIN(Th!)) - 0.25 * R!, 208 - 100 * (1 - 0.5 * SIN(Th!)) - 0.25 * R!)
NEXT J%
NEXT I%
FOR K%% = 0 TO NoArcs%%
MapFromNoseCone%(K%%, 0) = CINT(100 * COS(2 * _PI * K%% / NoArcs%%)) + 100 'x
MapFromNoseCone%(K%%, 1) = CINT(100 * SIN(2 * _PI * K%% / NoArcs%%)) + 100 'y
MapToNoseCone!(K%%, 0) = Rad%% * COS(2 * _PI * K%% / NoArcs%%) 'z
MapToNoseCone!(K%%, 1) = Rad%% * SIN(2 * _PI * K%% / NoArcs%%) 'x
MapToNoseCone!(K%%, 2) = (Rad%% - 1) * COS(2 * _PI * K%% / NoArcs%%) 'z
MapToNoseCone!(K%%, 3) = (Rad%% - 1) * SIN(2 * _PI * K%% / NoArcs%%) 'x
NEXT K%%
NoseCone& = HardwareImage&(TempImage&, True) 'Map this to rocket nose cone & base
'Fuel Pellet
FOR K%% = 0 TO 8
TempImage& = _NEWIMAGE(2 * PelletSize%% + 1, 2 * PelletSize%% + 1, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 225 - 20 * K%%), _RGBA32(90, 0, 90, 0)
CLS
CIRCLE (PelletSize%%, PelletSize%%), PelletSize%%
PAINT (PelletSize%%, PelletSize%%)
Pellets&(K%%) = HardwareImage&(TempImage&, True)
NEXT K%%
'Fuel stats: Pellet colour, pre-launch/launched/burnt out
FOR P% = 1 TO Sparks%
Fuel%%(P%, 0) = P% MOD 9 'Pellet colour factor
Fuel%%(P%, 1) = False 'Pre-launch state (stationary inside rocket)
Alpha! = RND * 2 * _PI
FuelStats!(P%, 0) = (Rad%% - PelletSize%%) * SIN(Alpha!) 'x
FuelStats!(P%, 2) = (Rad%% - PelletSize%%) * COS(Alpha!) 'z
FuelStats!(P%, 1) = -HalfLength%% + PelletSize%% 'y
NEXT P%
'Banner
TempImage& = _NEWIMAGE(940, 70, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (0, 0), "Rocket Launch Demonstration"
Banner0& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(300, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (80, 0), "Cape"
_PRINTSTRING (0, 65), "Canaveral"
Banner1& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(360, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (100, 0), "Mare"
_PRINTSTRING (0, 65), "Tranquillitatis"
Banner2& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(390, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (90, 0), "Rocket"
_PRINTSTRING (0, 65), "On Launchpad"
Banner3& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(200, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (0, 0), "Ignition"
Banner4& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(200, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (0, 0), "Lift-Off"
Banner5& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(380, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (80, 0), "Guided"
_PRINTSTRING (0, 65), "Pitch Forward"
Banner6& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(380, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (30, 0), "Propulsion"
_PRINTSTRING (90, 65), "Only"
Banner7& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(400, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (20, 0), "Fuel Used Up"
_PRINTSTRING (20, 65), "- Free Flight"
Banner8& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(380, 130, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 60, "bold")
_PRINTSTRING (40, 0), "At Maximum"
_PRINTSTRING (100, 65), "Altitude"
Banner9& = HardwareImage&(TempImage&, True)
TempImage& = _NEWIMAGE(860, 100, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(90, 0, 90, 0)
CLS
_FONT _LOADFONT(ENVIRON$("SYSTEMROOT") + "\Fonts\arial.ttf", 46, "bold")
_PRINTSTRING (0, 0), "That's One Small App From Magdha..."
Banner10& = HardwareImage&(TempImage&, True)
'Initial Conditions and dummy variables
Dum1%% = 0
Dum2%% = 0
Dum3%% = 0
Z! = 0
Y! = HalfLength%% + LauchHeight%
X! = 0
Vz! = 0
Vy! = 0
VFactor! = 2.5
N% = 0
Theta! = _PI / 2
g! = VSparks! * SIN(Theta!) / ((Sparks% - Ignition%) + (Sparks% * FRatio!))
Zara%% = False
Gamma! = -_PI / 5
Saturn%% = False
Fps%% = 120
'Screen
SCREEN _NEWIMAGE(1000, 850, 32)
_SCREENMOVE 50, 0
_DEST 0
_DISPLAYORDER _HARDWARE , _SOFTWARE
LOCATE 1, 1
PRINT "Altitude:"
LOCATE 2, 1
PRINT "Range:"
LOCATE 3, 1
PRINT "Pitch:"
Count& = 0
Paused%% = False
DoExit%% = False
WHILE NOT DoExit%%
_LIMIT Fps%%
K$ = INKEY$
IF K$ <> "" THEN
IF UCASE$(K$) = "P" THEN
Paused%% = NOT Paused%%
ELSEIF ASC(K$) = 27 THEN
DoExit%% = True
END IF
K$ = ""
END IF
IF NOT Paused%% THEN
Count& = Count& + 1
CALL ReadOut((Y!), 1)
CALL ReadOut((Z!), 2)
CALL ReadOut((Theta!), 3)
IF Count& > PreLaunch% THEN 'Start fuel ignition after set delay (while displaying information banners)
IF N% <= Sparks% THEN
'Using fuel
IF N% >= 1 THEN
Fuel%%(N%, 1) = True
FuelStats!(N%, 3) = Theta!
'Rotate by Theta/Phi about the x- axis
y1! = FuelStats!(N%, 1)
FuelStats!(N%, 2) = FuelStats!(N%, 2) * COS(Phi!) + y1! * SIN(Phi!) 'z
FuelStats!(N%, 1) = 0 - FuelStats!(N%, 2) * SIN(Phi!) + y1! * COS(Phi!) 'y
FuelStats!(N%, 2) = FuelStats!(N%, 2) + ZDisp! * Z! + LaunchPadZ% 'z
FuelStats!(N%, 1) = FuelStats!(N%, 1) + YDisp! * Y! + TranquilityBase% 'y
END IF
N% = N% + 1
'Thrust from fuel pellet ejection
VImp! = VSparks! / ((Sparks% - N%) + (Sparks% * FRatio!))
IF VImp! * SIN(Theta!) > g! THEN
'Rocket accelerates when thrust overcomes gravity
deltaVz! = VImp! * COS(Theta!)
deltaVy! = VImp! * SIN(Theta!) - g!
deltaZ! = Vz! + deltaVz! * deltaT! / 2
deltaY! = Vy! + deltaVy! * deltaT! / 2
Z! = Z! + deltaZ!
IF Z! < 0 THEN Z! = 0
Y! = Y! + deltaY!
Vz! = Vz! + deltaVz!
Vy! = Vy! + deltaVy!
'Rotate rocket body
Gamma! = Gamma! - 0.00265
'When half of fuel has been used allow a short period of guided pitch change
IF N% > Sparks% / 2 THEN
IF N% < (Sparks% / 2) + 500 THEN
'Guided tilting region
Theta! = Theta! - 0.00008 'This figure "derived" from trial & error
ELSE
'Angle determined by propulsion
Theta! = ATN(Vy! / Vz!)
END IF
END IF
END IF
ELSEIF Y! > 0 THEN
'Fuel used up - Flight is free parabolic curve
Gamma! = Gamma! - 0.003
deltaVz! = 0
deltaVy! = -g!
deltaZ! = Vz! + deltaVz! * deltaT! / 2
deltaY! = Vy! + deltaVy! * deltaT! / 2
Z! = Z! + deltaZ!
Y! = Y! + deltaY!
Vz! = Vz! + deltaVz!
Vy! = Vy! + deltaVy!
Theta! = ATN(Vy! / Vz!)
END IF
END IF
'Display the rocket
Phi! = _PI / 2 - Theta! 'The angle used to determine mapping
IF Saturn%% THEN
'Map Rocket
FOR K%% = 1 TO NoArcs%%
'Rocket Body
'Movement & Rotations
CALL Manoeuvre((MapToClinder!(K%% - 1, 0)), (MapToClinder!(K%%, 0)), (MapToClinder!(K%%, 0)), (MapToClinder!(K%% - 1, 0)), (MapToClinder!(K%% - 1, 1)), (MapToClinder!(K%%, 1)), (MapToClinder!(K%%, 1)), (MapToClinder!(K%% - 1, 1)), (HalfLength%%), (HalfLength%%), (-HalfLength%%), (-HalfLength%%), (True), x13!, x23!, x33!, x43!, y13!, y23!, y33!, y43!, z13!, z23!, z33!, z43!)
'Map to Display
_MAPTRIANGLE (MapFromCylinder%(NoArcs%% - K%% + 1), ApolloJ%)-(MapFromCylinder%(NoArcs%% - K%%), ApolloJ%)-(MapFromCylinder%(NoArcs%% - K%%), 0), Apollo11& TO(x13!, y13!, z13! - ZOffset%)-(x23!, y23!, z23! - ZOffset%)-(x33!, y33!, z33! - ZOffset%)
_MAPTRIANGLE (MapFromCylinder%(NoArcs%% - K%%), 0)-(MapFromCylinder%(NoArcs%% - K%% + 1), 0)-(MapFromCylinder%(NoArcs%% - K%% + 1), ApolloJ%), Apollo11& TO(x33!, y33!, z33! - ZOffset%)-(x43!, y43!, z43! - ZOffset%)-(x13!, y13!, z13! - ZOffset%)
'END IF
'Rocket Nocecone
'Movement & Rotations
CALL Manoeuvre(0, (MapToNoseCone!(K%%, 0)), (MapToNoseCone!(K%% - 1, 0)), Dum1%%, 0, (MapToNoseCone!(K%%, 1)), (MapToNoseCone!(K%% - 1, 1)), Dum2%%, (HalfLength%% + NoseHeight%), (HalfLength%%), (HalfLength%%), Dum3%%, (True), x14!, x24!, x34!, x44!, y14!, y24!, y34!, y44!, z14!, z24!, z34!, z44!)
'Map to Display
_MAPTRIANGLE (100, 100)-(MapFromNoseCone%(K%%, 0), MapFromNoseCone%(K%%, 1))-(MapFromNoseCone%(K%% - 1, 0), MapFromNoseCone%(K%% - 1, 1)), NoseCone& TO(x14!, y14!, z14! - ZOffset%)-(x24!, y24!, z24! - ZOffset%)-(x34!, y34!, z34! - ZOffset%)
'Rocket Base
'Movement & Rotations
CALL Manoeuvre(0, (MapToNoseCone!(K%%, 2)), (MapToNoseCone!(K%% - 1, 2)), Dum1%%, 0, (MapToNoseCone!(K%%, 3)), (MapToNoseCone!(K%% - 1, 3)), Dum2%%, (1 - HalfLength%%), (1 - HalfLength%%), (1 - HalfLength%%), Dum3%%, (False), x15!, x25!, x35!, x45!, y15!, y25!, y35!, y45!, z15!, z25!, z35!, z45!)
'Map to Display
_MAPTRIANGLE (100, 100)-(MapFromNoseCone%(K%%, 0), MapFromNoseCone%(K%%, 1))-(MapFromNoseCone%(K%% - 1, 0), MapFromNoseCone%(K%% - 1, 1)), NoseCone& TO(x15!, y15!, z15! - ZOffset%)-(x25!, y25!, z25! - ZOffset%)-(x35!, y35!, z35! - ZOffset%)
NEXT K%%
'Rocket Logo
FOR K%% = 1 TO 8
'Movement & Rotations
CALL Manoeuvre((MapToLogo!(K%% - 1, 0)), (MapToLogo!(K%%, 0)), (MapToLogo!(K%%, 0)), (MapToLogo!(K%% - 1, 0)), (MapToLogo!(K%% - 1, 1)), (MapToLogo!(K%%, 1)), (MapToLogo!(K%%, 1)), (MapToLogo!(K%% - 1, 1)), (HalfLength%%), (HalfLength%%), (-HalfLength%%), (-HalfLength%%), (True), x16!, x26!, x36!, x46!, y16!, y26!, y36!, y46!, z16!, z26!, z36!, z46!)
'Map to Display
_MAPTRIANGLE (MapFromLogo%(K%% - 1), 0)-(MapFromLogo%(K%%), 0)-(MapFromLogo%(K%%), ApolloJ%), ItsARocket& TO(x16!, y16!, z16! - ZOffset%)-(x26!, y26!, z26! - ZOffset%)-(x36!, y36!, z36! - ZOffset%)
_MAPTRIANGLE (MapFromLogo%(K%%), ApolloJ%)-(MapFromLogo%(K%% - 1), ApolloJ%)-(MapFromLogo%(K%% - 1), 0), ItsARocket& TO(x36!, y36!, z36! - ZOffset%)-(x46!, y46!, z46! - ZOffset%)-(x16!, y16!, z16! - ZOffset%)
NEXT K%%
'Propellant Pellets - display and move
FOR P% = 1 TO Sparks%
IF Fuel%%(P%, 1) THEN
'Map Pellet if it is active
_MAPTRIANGLE (0, 0)-(PelletSize%%, 0)-(PelletSize%%, PelletSize%%), Pellets&(Fuel%%(P%, 0)) TO(FuelStats!(P%, 0) - PelletSize%%, FuelStats!(P%, 1) + PelletSize%%, FuelStats!(P%, 2) - ZOffset%)-(FuelStats!(P%, 0) + PelletSize%%, FuelStats!(P%, 1) + PelletSize%%, FuelStats!(P%, 2) - ZOffset%)-(FuelStats!(P%, 0) + PelletSize%%, FuelStats!(P%, 1) - PelletSize%%, FuelStats!(P%, 2) - ZOffset%)
_MAPTRIANGLE (PelletSize%%, PelletSize%%)-(0, PelletSize%%)-(0, 0), Pellets&(Fuel%%(P%, 0)) TO(FuelStats!(P%, 0) + PelletSize%%, FuelStats!(P%, 1) - PelletSize%%, FuelStats!(P%, 2) - ZOffset%)-(FuelStats!(P%, 0) - PelletSize%%, FuelStats!(P%, 1) - PelletSize%%, FuelStats!(P%, 2) - ZOffset%)-(FuelStats!(P%, 0) - PelletSize%%, FuelStats!(P%, 1) + PelletSize%%, FuelStats!(P%, 2) - ZOffset%)
'Propel pellet backwards in the direction opposite to that of the rocket at that time
FuelStats!(P%, 1) = FuelStats!(P%, 1) - VSparks! * VFactor! * SIN(FuelStats!(P%, 3)) 'y
FuelStats!(P%, 2) = FuelStats!(P%, 2) - VSparks! * VFactor! * COS(FuelStats!(P%, 3)) 'z
IF FuelStats!(P%, 1) < TranquilityBase% - 10 THEN Fuel%%(P%, 1) = False
END IF
NEXT P%
END IF
END IF
'Map Landscapes
_MAPTRIANGLE (0, 0)-(1167, 0)-(1167, 850), Canaveral& TO(-500, TranquilityBase%, -3000 - ZOffset%)-(500, TranquilityBase%, -3000 - ZOffset%)-(500, TranquilityBase%, -50 - ZOffset%)
_MAPTRIANGLE (1167, 850)-(0, 850)-(0, 0), Canaveral& TO(500, TranquilityBase%, -50 - ZOffset%)-(-500, TranquilityBase%, -50 - ZOffset%)-(-500, TranquilityBase%, -3000 - ZOffset%)
_MAPTRIANGLE (0, 0)-(626, 0)-(626, 758), Tranquility& TO(-500, TranquilityBase%, 100 - ZOffset%)-(500, TranquilityBase%, 100 - ZOffset%)-(500, TranquilityBase%, 800 - ZOffset%)
_MAPTRIANGLE (626, 758)-(0, 758)-(0, 0), Tranquility& TO(500, TranquilityBase%, 800 - ZOffset%)-(-500, TranquilityBase%, 800 - ZOffset%)-(-500, TranquilityBase%, 100 - ZOffset%)
'Sounds
SELECT CASE Count&
CASE PreLaunch%
IF DoBlast%% THEN _SNDPLAY Blast&
CASE 2950
_SNDPLAY Zarathustra&
CASE 13850
_SNDPLAY Landed&
CASE 14250
_SNDPLAY GiantLeap&
END SELECT
'Banners
SELECT CASE Count&
CASE IS <= 350
_PUTIMAGE (100, 120), Banner0&
CASE 400 TO 600
IF Count& = 400 THEN _FREEIMAGE Banner0&
_PUTIMAGE (680, 400), Banner1&
CASE 650 TO 850
IF Count& = 650 THEN _FREEIMAGE Banner1&
_PUTIMAGE (400, 700), Banner2&
CASE 900 TO 1100
IF Count& = 900 THEN
_FREEIMAGE Banner2&
Saturn%% = True
END IF
_PUTIMAGE (550, 400), Banner3&
CASE PreLaunch% TO PreLaunch% + Ignition%
IF Count& = PreLaunch% THEN
_FREEIMAGE Banner3&
Fps%% = 60 'Temporarily slow down display to more readily observe the ignition stage
VFactor! = 5
END IF
_PUTIMAGE (400, 120), Banner4&
CASE PreLaunch% + Ignition% + ArtificialDelay% TO PreLaunch% + Ignition% + ArtificialDelay% + 450
IF Count& = PreLaunch% + Ignition% + ArtificialDelay% THEN
_FREEIMAGE Banner4&
Fps%% = 120
VFactor! = 2.5
END IF
_PUTIMAGE (400, 110), Banner5&
CASE 3751 TO 4230
IF Count& = 3751 THEN _FREEIMAGE Banner5&
_PUTIMAGE (340, 100), Banner6&
CASE 4250 TO 4500
IF Count& = 4250 THEN _FREEIMAGE Banner6&
_PUTIMAGE (340, 90), Banner7&
CASE 6251 TO 6500
IF Count& = 6251 THEN _FREEIMAGE Banner7&
_PUTIMAGE (340, 60), Banner8&
CASE 9270 TO 9500
IF Count& = 9270 THEN _FREEIMAGE Banner8&
_PUTIMAGE (340, 300), Banner9&
CASE 14250 TO 14550
IF Count& = 13200 THEN _FREEIMAGE Banner9&
_PUTIMAGE (70, 150), Banner10&
END SELECT
_DISPLAY
WEND
SYSTEM
FUNCTION HardwareImage& (ImageName&, Scrap%%)
HardwareImage& = _COPYIMAGE(ImageName&, 33)
IF Scrap%% THEN _FREEIMAGE ImageName&
END FUNCTION
SUB ReadOut (E!, C%%)
IF C%% = 3 THEN
E1! = E! * 180 / _PI
ELSE
E1! = E!
IF E1! < 0 THEN E1! = 0
END IF
Q% = CINT(E1!)
S$ = STR$(Q%)
LOCATE C%%, 11
PRINT " "
LOCATE C%%, 16 - LEN(S$)
PRINT S$
END SUB
SUB Manoeuvre (z10!, z20!, z30!, z40!, x10!, x20!, x30!, x40!, y10!, y20!, y30!, y40!, MagicRoundabout%%, x19!, x29!, x39!, x49!, y19!, y29!, y39!, y49!, z19!, z29!, z39!, z49!)
IF MagicRoundabout%% THEN
'Rotate about y-axis
z1! = z10! * COS(Gamma!) + x10! * SIN(Gamma!)
x1! = -z10! * SIN(Gamma!) + x10! * COS(Gamma!)
z2! = z20! * COS(Gamma!) + x20! * SIN(Gamma!)
x2! = -z20! * SIN(Gamma!) + x20! * COS(Gamma!)
z3! = z30! * COS(Gamma!) + x30! * SIN(Gamma!)
x3! = -z30! * SIN(Gamma!) + x30! * COS(Gamma!)
z4! = z40! * COS(Gamma!) + x40! * SIN(Gamma!)
x4! = -z40! * SIN(Gamma!) + x40! * COS(Gamma!)
y1! = y10!
y2! = y20!
y3! = y30!
y4! = y40!
ELSE
z1! = z10!
x1! = x10!
z2! = z20!
x2! = x20!
z3! = z30!
x3! = x30!
z4! = z40!
x4! = x40!
y1! = y10!
y2! = y20!
y3! = y30!
y4! = y40!
END IF
'Then rotate by Phi about the x- axis (pitch)
z12! = z1! * COS(Phi!) + y1! * SIN(Phi!)
y12! = -z1! * SIN(Phi!) + y1! * COS(Phi!)
z22! = z2! * COS(Phi!) + y2! * SIN(Phi!)
y22! = -z2! * SIN(Phi!) + y2! * COS(Phi!)
z32! = z3! * COS(Phi!) + y3! * SIN(Phi!)
y32! = -z3! * SIN(Phi!) + y3! * COS(Phi!)
z42! = z4! * COS(Phi!) + y4! * SIN(Phi!)
y42! = -z4! * SIN(Phi!) + y4! * COS(Phi!)
x12! = x1!
x22! = x2!
x32! = x3!
x42! = x4!
'Then add X!, Y! & Z!
x19! = x12! + X!
x29! = x22! + X!
x39! = x32! + X!
x49! = x42! + X!
y19! = y12! + YDisp! * Y! + TranquilityBase%
y29! = y22! + YDisp! * Y! + TranquilityBase%
y39! = y32! + YDisp! * Y! + TranquilityBase%
y49! = y42! + YDisp! * Y! + TranquilityBase%
z19! = z12! + ZDisp! * Z! + LaunchPadZ%
z29! = z22! + ZDisp! * Z! + LaunchPadZ%
z39! = z32! + ZDisp! * Z! + LaunchPadZ%
z49! = z42! + ZDisp! * Z! + LaunchPadZ%
END SUB
When I discovered _MAPTRIANGLE(3D) I found it interesting. The fun is working out the appropriate mapping to go from a 2D image to a 3D image. Skilled QB64 programmers will use OpenGL but that has remained beyond me, and at present I seem to be in a _MAPTRIANGLE(3D) - Conic Sections coding phase. My two previous programs (https://qb64phoenix.com/forum/showthread.php?tid=4025, https://qb64phoenix.com/forum/showthread.php?tid=4052) had objects moving in hyperbolic paths and then in a 3D circular path. In this program I have an object moving along a parabolic path, and I'm investigating elliptical motion.

