Lunar Lander Code

 

% Samuel Georgal
% Lunar Lander
% 4/20/22


close all; clear; clc
global f dtheta dx dy mf theta
global Vxbox Vybox Fuelbox Thrustbox Thetabox Dthetabox
% Creates required variables
xmax = 500;
xmin = 0;
ymax = xmax;
f = 0;
Xs = 50;
Ys = 480;
c = 0;
l = 0;
dx = 10;
dy = 0;
ax = 0;
ay = 0;
g = 1.62;
R = 1.738*10^6;
mf = 3500;
m0 = 4900;
m = m0 + mf;
Tmax = 33000;
fdeg = .00328;
theta = -90;
dt = .01;
dtheta = 0;
% Create Figure window
KeyFig = figure('Units','pixels','Position', [0, 0, 1000, 820]);
% formats figure
axes(KeyFig,'Units', 'pixels', 'Position', [0,0,820,820],'color','k');
axis([xmin, xmax, 0, ymax])
axis manual
hold on
% Register KeyPressFcn to allow figure window to respond to keypresses
set(KeyFig, 'WindowKeyPressFcn', @KeyDownListener)
% Graphs lunar surface
y = graph;
% makes ship and thrust shape
ShipShape = [ -5.00, -3.00, -3.00, 3.00, 3.00, 5.00, 3.00, 1.00, 3.00, 3.00, 1.00, ...
-1.00, -3.00, -3.00, -1.00, -3.00; 0.00, 2.00, 1.00, 1.00, 2.00, 0.00, 4.00, ...
4.00, 6.00, 8.00, 10.00, 10.00, 8.00, 6.00, 4.00, 4.00];
ShipThrust = [-3.00,0,3;0,-16,0];
% scales ship and thrust size
ShipScale = 1.2;
SHIP = ShipScale*ShipShape;
Thrust = ShipThrust * f;
% Creates patch for ship and thrust
Ship_Patch = patch(SHIP(1,:)+Xs, SHIP(2,:)+Ys, 'w');
Ship_Thrust = patch(Thrust(1,:)+Xs, Thrust(2,:)+Ys, 'y');
% Creates editable text boxes for code to show important values
Control;
errordlg(['Land on the Moon! Use WASD or arrow keys to control lander. ' ...
'Land slowly and upright to complete. Have fun!!']);
% Runs Game
while (c == 0) && (l == 0)
% Calculates ship movement and position
ay = ((f*Tmax*cosd(theta))/m)-(g-((dx^2)/R));
ax = (f*Tmax*sind(theta))/m;
dm = f*Tmax*fdeg;
Xs = Xs + dx*dt;
Ys = Ys + dy*dt;
xint = round(Xs);
dx = dx + ax*dt;
dy = dy + ay*dt;
mf = mf - dm*dt;
m = m0 + mf;
theta = theta + dtheta;
if theta >= 180
theta = -180+(theta-180);
elseif theta <= -180
theta = 180-(theta+180);
end
% Makes required changes to patches and updates the patches
Thrust = ShipThrust * f;
RtnMtrx = [-cosd(-theta), -sind(-theta); -sind(-theta), cosd(-theta)];
Ship_R = RtnMtrx*SHIP;
Thrust_R = RtnMtrx*Thrust;
set(Ship_Patch, 'Xdata', Ship_R(1,:)+Xs, 'Ydata', Ship_R(2,:)+Ys)
set(Ship_Thrust, 'Xdata', Thrust_R(1,:)+Xs, 'Ydata', Thrust_R(2,:)+Ys)
% Updates information boxes
Vxbox.String = num2str(dx,'%.1f');
Vybox.String = num2str(dy,'%.1f');
Fuelbox.String = num2str(mf,'%.0f');
Thrustbox.String = num2str(100*f,'%.0f');
Thetabox.String = num2str(theta,'%.0f');
Dthetabox.String = num2str(100*dtheta,'%.0f');
% Keeps ship inbounds and checks for crashing or landing
if Ys >= ymax
Ys = ymax;
elseif Ys <= y(xint)
if (abs(dx) >= 3) || (abs(dy) >= 10)
c = 1;
elseif (abs(theta) > 10)
c = 1;
else
l = 1;
end
end
if Xs >= xmax
Xs = xmax;
elseif Xs <= xmin
Xs = xmin;
end
% Pauses by required time
pause(dt)
end
% Checks if landed or crashed and responds accordingly
if c == 1
th = 0:pi/50:2*pi;
for r = 5:50
xunit = r * cos(th) + Xs;
yunit = r * sin(th) + Ys+2;
plot(xunit, yunit,'r');
fill(xunit, yunit, 'r');
pause(.03)
end
pause(2);
errordlg('Mission Failed!');
else
set(Ship_Thrust, 'Xdata', 0, 'Ydata', 0)
set(Ship_Patch, 'Xdata', SHIP(1,:)+Xs, 'Ydata', SHIP(2,:)+Ys)
errordlg('Mission Complete!');
end
%% Functions
% Key-press 'listener' function
function KeyDownListener(src, event)
% triggered by pressing a key on the keyboard
global f dtheta
% Updates Keyid so key input is registered
KeyID = event.Key;
% Updates correct paramater depending on key input
switch KeyID
case 'w'
f = f + .04;
if f >1
f = 1;
end
case 's'
f = f- .04;
if f < 0
f = 0;
end
case 'a'
dtheta = dtheta - 0.1;
case 'd'
dtheta = dtheta + 0.1;
case 'uparrow'
f = f + .04;
if f >1
f = 1;
end
case 'downarrow'
f = f- .04;
if f < 0
f = 0;
end
case 'leftarrow'
dtheta = dtheta - 0.1;
case 'rightarrow'
dtheta = dtheta + 0.1;
end
KeyID = ' ';
end
function [y] = graph
% Randomly generates a terrain with different probabilities for each dy
y = NaN(1,500);
x = [1:500];
y(1) = randi(200);
for i = 2:3:500
chg = randi(10);
switch chg
case 1
y(i) = y(i-1)-randi(1)+randi(1);
case 2
y(i) = y(i-1)-randi(1)+randi(1);
case 3
y(i) = y(i-1)-randi(1)+randi(1);
case 4
y(i) = y(i-1)-randi(1)+randi(1);
case 5
y(i) = y(i-1)-randi(1)+randi(1);
case 6
y(i) = y(i-1)-randi(3)+randi(3);
case 7
y(i) = y(i-1)-randi(3)+randi(3);
case 8
y(i) = y(i-1)-randi(5)+randi(5);
case 9
y(i) = y(i-1)-randi(5)+randi(5);
case 10
y(i) = y(i-1)-randi(10)+randi(10);
end
%calculates next 3 points
dy = y(i)-y(i-1);
y(i+1) = y(i)+dy;
y(i+2) = y(i+1)+dy;
% ensures terrain stays within bounds
if y(i+2) <= 0
y(i+2) = 5;
elseif y(i+2) >= 350
y(i+2) = 345;
end
if y(i) <= 0
y(i) = 5;
elseif y(i) >= 350
y(i) = 345;
end
end
yc = y(1,1:500);
% Plots result
plot(x,yc,'w','LineWidth',3)
end
function Control
global dx dy mf f theta dtheta
global Vxbox Vybox Fuelbox Thrustbox Thetabox Dthetabox
% Creates a box for each information type
Vxbox = uicontrol('Style', 'edit', 'String', num2str(dx,'%.1f'), ...
'Position', [880, 460, 80, 20], 'Enable', 'inactive');
uicontrol('Style', 'text', 'String', 'Horizontal Velocity (m/s)', ...
'Position', [845, 480, 150, 20])
Vybox = uicontrol('Style', 'edit', 'String', num2str(dy,'%.1f'), ...
'Position', [880, 510, 80, 20], 'Enable', 'inactive');
uicontrol('Style', 'text', 'String', 'Vertical Velocity (m/s)', ...
'Position', [845, 530, 150, 20])
Fuelbox = uicontrol('Style', 'edit', 'String', num2str(mf,'%.0f'), ...
'Position', [880, 560, 80, 20], 'Enable', 'inactive');
uicontrol('Style', 'text', 'String', 'Fuel (kg)', ...
'Position', [845, 580, 150, 20])
Thrustbox = uicontrol('Style', 'edit', 'String', num2str(f,'%.2f'), ...
'Position', [880, 610, 80, 20], 'Enable', 'inactive');
uicontrol('Style', 'text', 'String', '% maximum thrust', ...
'Position', [845, 630, 150, 20])
Thetabox = uicontrol('Style', 'edit', 'String', num2str(theta,'%.1f'), ...
'Position', [880, 660, 80, 20], 'Enable', 'inactive');
uicontrol('Style', 'text', 'String', 'Angle', ...
'Position', [845, 680, 150, 20])
Dthetabox = uicontrol('Style', 'edit', 'String', num2str(100*dtheta,'%.1f'), ...
'Position', [880, 710, 80, 20], 'Enable', 'inactive');
uicontrol('Style', 'text', 'String', 'Rotation Speed (degrees/s)', ...
'Position', [845, 730, 150, 20])
end

Comments