Tutorial Coding a Lunar Lander from the ground up (when you don't know how to code)

Longjap

New member
Joined
Jun 8, 2011
Messages
183
Reaction score
0
Points
0
Hey Hlynkacg,

thanks for your tut! I'm currently at part 6, and I have made a satellite while following your instructions. I have some problem making a scale animation work.
It's basically the same as your example except it uses one mesh, but still via a mesh handle. Now I know this animation works from my spacecraft4 version but somehow it doesn't do what I expect. There are no problems compiling it and the debug works fine.

Code:
Cubesat6U_NEA::Cubesat6U_NEA (OBJHANDLE hVessel, int flightmodel)
: VESSEL3 (hVessel, flightmodel)
{	// Load Exterior meshes
	mh_cubesat		= oapiLoadMeshGlobal("SLS_2016/Cubesat6U_NEA");
    // Solar Sail animation
	static UINT SailGrp	= 48;		// participating groups

	static MGROUP_SCALE	mgt_Sail ( mesh_Full, &SailGrp, 1, _V(0.0,0.0,0.0), _V(180.0,1.0,180.0));
	
	anim_Sail = CreateAnimation(0);
	AddAnimationComponent ( anim_Sail, 0.0f, 1.0f, &mgt_Sail);

}

Cubesat6U_NEA::~Cubesat6U_NEA ()
{
}
Code:
void Cubesat6U_NEA::clbkPostStep (double simt, double simdt, double mjd) 
// Solar Sail control logic
{
	if (sail_proc < 0)			// If process value is less than 0...
	{
		SailStatus = CLOSED;	// ...set status to "CLOSED"
		sail_proc = 0;		// and process value to 0
	}

	else if (sail_proc > 1)	// If process value is greater than 1...
	{
		SailStatus = OPEN;	// ...set status to "OPEN"
		sail_proc = 1;		// and process value to 1
	}

	if (SailStatus > CLOSED)	
	{
		double	delta = simdt / 10;	

		if (SailStatus == OPENING)		// if Status equals "OPENING"...
		{
			sail_proc += delta;	// ...add delta to process value
		}
		
		if (SailStatus == CLOSING)		// if Status equals "CLOSING"...
		{
			sail_proc -= delta;	// ...subtract it.
		}

		SetAnimation( anim_Sail, sail_proc);	// Apply process value to animation.
	}

	// Debuggery
	sprintf(oapiDebugString(), "Sail Status %0.0f, sail_proc %0.3f", (float)SailStatus, sail_proc);
	}
Code:
int  Cubesat6U_NEA::clbkConsumeBufferedKey (DWORD key, bool down, char *kstate)
{	// Open sail when [shift + 1] is pressed.
	if (key == OAPI_KEY_1  && down && KEYMOD_SHIFT(kstate) && !KEYMOD_CONTROL (kstate) && !KEYMOD_ALT(kstate)) // [1] is down, with [shift], no [ctrl], no [alt]
	{
		if (SailStatus == CLOSED) SailStatus = OPENING;	// If the sail is closed, open it
		else SailStatus = CLOSING;							// If not, close it 
		return 1;
	}

	return 0; // if no keys are pressed the function returns '0' and nothing happens
}
Code:
// ==============================================================
//                 ORBITER MODULE: ShuttlePB
//                  Part of the ORBITER SDK
//          Copyright (C) 2002-2004 Martin Schweiger
//                   All rights reserved
//
// ShuttlePB.cpp
// Control module for ShuttlePB vessel class
//
// Notes:
// This is an example for a "minimal" vessel implementation which
// only overloads the clbkSetClassCaps method to define vessel
// capabilities and otherwise uses the default VESSEL class
// behaviour.
// ==============================================================

#define STRICT
#define ORBITER_MODULE

#include "orbitersdk.h"

// ==============================================================
// Some vessel parameters
// ==============================================================
const double  PB_SIZE       = 3.5;             // mean radius [m]
const VECTOR3 PB_CS         = {10.5,15.0,5.8}; // x,y,z cross sections [m^2]
const VECTOR3 PB_PMI        = {2.28,2.31,0.79};// principal moments of inertia (mass-normalised) [m^2]
const VECTOR3 PB_RD         = {0.025,0.025,0.02};//{0.05,0.1,0.05};  // rotation drag coefficients
const double  PB_EMPTYMASS  = 500.0;           // empty vessel mass [kg]
const double  PB_FUELMASS   = 750.0;           // max fuel mass [kg]
const double  PB_ISP        = 5e4;             // fuel-specific impulse [m/s]
const VECTOR3 PB_COP        = {0,0,0};//{0,0,-0.1};      // centre of pressure for airfoils [m]
const double  PB_VLIFT_C    = 2.0;             // chord length [m]
const double  PB_VLIFT_S    = 2.0;             // wing area [m^2]
const double  PB_VLIFT_A    = 2.5;             // wing aspect ratio
const double  PB_HLIFT_C    = 2.0;             // chord length [m]
const double  PB_HLIFT_S    = 1.5;             // wing area [m^2]
const double  PB_HLIFT_A    = 2.0;             // wing aspect ratio

const double  PB_MAXMAINTH  = 3e4;             
const double  PB_MAXHOVERTH = 1.5e4;
const double  PB_MAXRCSTH   = 2e2;

const VECTOR3 PB_DOCK_POS   = {0,1.3,-1};      // docking port location [m]
const VECTOR3 PB_DOCK_DIR   = {0,1,0};         // docking port approach direction
const VECTOR3 PB_DOCK_ROT   = {0,0,-1};        // docking port alignment direction
const VECTOR3 LM_ASC_OFFSET	= { 0.00, 1.44, 0.00};	// Offset of Ascent stage COG from combined COG
const VECTOR3 LM_DES_OFFSET	= { 0.00,-0.80, 0.00};	// Offset of Descent stage COG from combined COG

// Define impact convex hull
static const DWORD ntdvtx = 12;
static TOUCHDOWNVTX tdvtx[ntdvtx] = {
	{_V( 0,  -1.5, 2  ), 2e4, 1e3, 1.6, 1},
	{_V(-1,  -1.5,-1.5), 2e4, 1e3, 3.0, 1},
	{_V( 1,  -1.5,-1.5), 2e4, 1e3, 3.0, 1},
	{_V(-0.5,-0.75,3  ), 2e4, 1e3, 3.0},
	{_V( 0.5,-0.75,3  ), 2e4, 1e3, 3.0},
	{_V(-2.6,-1.1,-1.9), 2e4, 1e3, 3.0},
	{_V( 2.6,-1.1,-1.9), 2e4, 1e3, 3.0},
	{_V(-1,   1.3, 0  ), 2e4, 1e3, 3.0},
	{_V( 1,   1.3, 0  ), 2e4, 1e3, 3.0},
	{_V(-1,   1.3,-2  ), 2e4, 1e3, 3.0},
	{_V( 1,   1.3,-2  ), 2e4, 1e3, 3.0},
	{_V( 0,   0.3,-3.8), 2e4, 1e3, 3.0}
};

// Calculate lift coefficient [Cl] as a function of aoa (angle of attack) over -Pi ... Pi
// Implemented here as a piecewise linear function
double LiftCoeff (double aoa)
{
	int i;
	const int nlift = 9;
	static const double AOA[nlift] = {-180*RAD,-60*RAD,-30*RAD,-1*RAD,15*RAD,20*RAD,25*RAD,60*RAD,180*RAD};
	static const double CL[nlift]  = {       0,      0,   -0.1,     0,   0.2,  0.25,   0.2,     0,      0};
	static const double SCL[nlift] = {(CL[1]-CL[0])/(AOA[1]-AOA[0]), (CL[2]-CL[1])/(AOA[2]-AOA[1]),
		                              (CL[3]-CL[2])/(AOA[3]-AOA[2]), (CL[4]-CL[3])/(AOA[4]-AOA[3]),
									  (CL[5]-CL[4])/(AOA[5]-AOA[4]), (CL[6]-CL[5])/(AOA[6]-AOA[5]),
									  (CL[7]-CL[6])/(AOA[7]-AOA[6]), (CL[8]-CL[7])/(AOA[8]-AOA[7])};
	for (i = 0; i < nlift-1 && AOA[i+1] < aoa; i++);
	return CL[i] + (aoa-AOA[i])*SCL[i];
}

// ==============================================================
// Cubesat6U_NEA class interface
// ==============================================================

class Cubesat6U_NEA: public VESSEL3 {
public:
	Cubesat6U_NEA (OBJHANDLE hVessel, int flightmodel);
	~Cubesat6U_NEA ();

	// Orbiter CallBack Functions
	void	clbkSetClassCaps (FILEHANDLE cfg);
    void	clbkPostStep(double simt, double simdt, double mjd);
    int		clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);	// Process keyboard inputs

private:
	//Vessel state variables
	enum		sailstate {CLOSED, OPEN, CLOSING, OPENING} SailStatus;
    
	//Animations
	UINT		anim_Sail, anim_Antenna;
	double		sail_proc;

	MESHHANDLE	mh_cubesat; // Mesh handles
	UINT	mesh_Full;		// Cubesat mesh
};
Can you see where I take the wrong turn?
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
35,549
Reaction score
65
Points
138
Location
Wolfsburg
You have missed to initialize the variable mesh_Full, its value should be random because of that.

Always initialize ALL your variables in the constructor of your vessel, this saves you a lot of headache.
 

Longjap

New member
Joined
Jun 8, 2011
Messages
183
Reaction score
0
Points
0
You have missed to initialize the variable mesh_Full, its value should be random because of that.

Always initialize ALL your variables in the constructor of your vessel, this saves you a lot of headache.
Uhm... Initialize? :embarrassed::lol: Like in the sourcefile:
Code:
mesh_Full = mh_cubesat;
?
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
35,549
Reaction score
65
Points
138
Location
Wolfsburg
Uhm... Initialize? :embarrassed::lol: Like in the sourcefile:
Code:
mesh_Full = mh_cubesat;
?
No... we are in a more or less strongly typing world, so UINT is never MESH_HANDLE. UINT is an abbreviation in C++ for unsigned int, so you can simply set it to zero for the start.
 

Notebook

Addon Developer
Addon Developer
Donator
Joined
Nov 20, 2007
Messages
11,068
Reaction score
59
Points
123
An obvious question, probably so obvious its stupid.

Why doesn't the compiler offer the option to set all declarations to a valid value?

INT = 0
Double = 0.0
and so on for all types.

Not overwriting any values already put in of course.

Thanks, N.
 

Longjap

New member
Joined
Jun 8, 2011
Messages
183
Reaction score
0
Points
0
:thumbup: It works!
Holy moly this is daunting, but moving on. The idea of e-v-e-n-t-u-a-l-l-y speaking this fluently and getting creative with it is really nice. But right now this is like learning Chinese.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
35,549
Reaction score
65
Points
138
Location
Wolfsburg
An obvious question, probably so obvious its stupid.

Why doesn't the compiler offer the option to set all declarations to a valid value?

INT = 0
Double = 0.0
and so on for all types.

Not overwriting any values already put in of course.

Thanks, N.
Because that is still a common cause for errors. Also it is too implicit for the style of C++.

In other languages, the compiler can simply warn you of you using uninitialized variables - in C and C++, its impossible, because of the pointers.
 

gattispilot

Addon Developer
Addon Developer
Joined
Oct 17, 2007
Messages
5,737
Reaction score
57
Points
123
Location
Dallas, TX
I have noticed in compiling in orbiter 2016 and VS2013 I get a message that a variable was uninitialized in debug mode
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
35,549
Reaction score
65
Points
138
Location
Wolfsburg
I have noticed in compiling in orbiter 2016 and VS2013 I get a message that a variable was uninitialized in debug mode
Yes, but you should not rely on that and this feature is limited in C++.
 

Saundr

New member
Joined
Mar 14, 2018
Messages
1
Reaction score
0
Points
0
The answer is simple, Lunar Landers have two stages and if want those stages to seperate at some point it is much 
 efficient to load multiple meshs and then add/remove them from the vessel as needed then
 
Top