image thumbnail

Moon Lander Matlab Game-Example of getting keypressed

by

 

06 Nov 2012 (Updated )

Lunar Lander game in Matlab, fully functional, and an example of how to get keypressed in figures.

Moon01.m
function Moon01
%Version 0.2 (beta, so please, give feedback).
%
%This is a game and also an example of how to read/use keypress
%functionality from figures.
%
%This is a tribute to Moon Lander[1], without any lucrative pourpouse.
%
%The game opens a figure with the spaceship that must land on the square
%avoiding hitting the land.
%
%Use the arrows to turn the spaceship and the spacebar to fire the engine.
%
%
%  References:
%  [1] Lunar Lander, Game,
%      http://en.wikipedia.org/wiki/Lunar_Lander_%28video_game%29
%
%This function was written by :
%                             Hctor Corte
%                             B.Sc. in physics 2010
%                             M.Sc. in Complex physics systems 2012
%                             NPL (National Physical Laboratory), London,
%                             United kingdom.
%                             Email: leo_corte@yahoo.es
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%First prepare Figure and axes.
%Next create figure and prepare it for fun.
figure('MenuBar','none','Color','black',...
    'Resize','off','name','Moon Lander','position',[50,50,800,500],...
    'CloseRequestFcn','global j;j=1;','BackingStore','on','keypressfcn',@keypress,...
    'KeyReleaseFcn',@keyrelease);
%When BackingStore is on, MATLAB stores a copy of the Figure window in an off-screen pixel buffer. When obscured parts of the Figure window are exposed, MATLAB copies the window contents from this buffer rather than regenerating the objects on the screen.
%Using keypressfcn we can take control in real time of the game.
axis([0,80,0,50])
set(gca,'color',[0 0 0])
%%%





%%%Next define variables for spaceship terrain and physics.
global spaceship terrain dt j
%This is just to stop the while
j=0;
%Define update interval (this can be adjust to faster computers)
dt=0.05;
%Define state of spaceship
%Position
spaceship.x=40;
spaceship.y=40;
%Velocity
spaceship.vx=0;
spaceship.vy=0;
%Rotation
spaceship.angle=pi/2;
%Engine on/off
spaceship.fire=0;
%Fuel
spaceship.fuel=500;

%These are related to the win/lose state of the game.
spaceship.physics=1;
spaceship.win=0;
spaceship.crash=0;

%These are for drawing the spaceship.
spaceship.Tx=[-0.5 0.5 0];
spaceship.Ty=[-0.25 -0.25 0.95];
spaceship.RTx=spaceship.Tx;
spaceship.RTy=spaceship.Ty;
spaceship.Ux=[-0.5 0.5 0.75 0.75 0.5 -0.5 -0.75 -0.75];
spaceship.Uy=[0.25 00.25 0.5 0.75 1 1 0.75 0.5];
spaceship.RUx=spaceship.Ux;
spaceship.RUy=spaceship.Uy;

%This are for generating the landing pad and the terrain.
%First the land.
terrain.xx=linspace(0,80,1000);
terrain.yy=20+16*sin(0.1*(terrain.xx+10*rand())).*sin(0.4*terrain.xx+10*rand())+0.1*rand(1,1000).*sin(0.22*terrain.xx);
%Then the landing pad in the correct possition.
terrain.wx=80*rand();
i=min(find(min((terrain.xx-terrain.wx).^2)==(terrain.xx-terrain.wx).^2)) ;
terrain.wy=terrain.yy(i)+0.5;

intro(); %This just show a little intro to the game.
while 1<2
    %This is the main bucle, it calls all the functions we need to play
    %(also the keypress function is allways working).
    check();
    if spaceship.physics==1
        physics();
    end
    render();
    if    spaceship.fire==1;
        engine_sound();
    
    end
    
    pause(dt)
    cla
    if j==1;
        clear spaceship terrain
        delete(gcf)
        break
    end
end
end

function intro()
%This is just a function to show the tittle at the begining, and waits
%until a key is pressed.
global spaceship

hold on
spaceship.RTx=cos(spaceship.angle-pi/2)*spaceship.Tx-sin(spaceship.angle-pi/2)*spaceship.Ty;
spaceship.RTy=sin(spaceship.angle-pi/2)*spaceship.Tx+cos(spaceship.angle-pi/2)*spaceship.Ty;

fill(spaceship.x+6*spaceship.RTx,spaceship.y+6*spaceship.RTy,'g');

spaceship.RUx=cos(spaceship.angle-pi/2)*spaceship.Ux-sin(spaceship.angle-pi/2)*spaceship.Uy;
spaceship.RUy=sin(spaceship.angle-pi/2)*spaceship.Ux+cos(spaceship.angle-pi/2)*spaceship.Uy;

fill(spaceship.x+6*spaceship.RUx,spaceship.y+6*spaceship.RUy,'w');
text(15,29.5,'Moon Lander','color','b','FontSize',49)
text(15,30,'Moon Lander','color','y','FontSize',50)
text(15,10,'Press Any key to Start','color','w','FontSize',30)

waitforbuttonpress ;

end

function render()
%This puts every graphic in the figure.
global spaceship terrain


hold on
%Terrain
area(terrain.xx,terrain.yy)
%Platform
plot(terrain.wx,terrain.wy,'Sw','markersize',30,'MarkerFaceColor','k')


if spaceship.crash==0
    %If the spaceship is not crashed, this draws the spacehip (rotated if
    %necessary)
    spaceship.RTx=cos(spaceship.angle-pi/2)*spaceship.Tx-sin(spaceship.angle-pi/2)*spaceship.Ty;
    spaceship.RTy=sin(spaceship.angle-pi/2)*spaceship.Tx+cos(spaceship.angle-pi/2)*spaceship.Ty;
    
    fill(spaceship.x+2*spaceship.RTx,spaceship.y+2*spaceship.RTy,'g');
    
    spaceship.RUx=cos(spaceship.angle-pi/2)*spaceship.Ux-sin(spaceship.angle-pi/2)*spaceship.Uy;
    spaceship.RUy=sin(spaceship.angle-pi/2)*spaceship.Ux+cos(spaceship.angle-pi/2)*spaceship.Uy;
    
    fill(spaceship.x+2*spaceship.RUx,spaceship.y+2*spaceship.RUy,'w');
    
    
    if spaceship.win==1
        
        title('Perfect Landing!','color','b')
        
    else
        if spaceship.fire==1
            %This is for drawing the fire of the engine.
            plot(spaceship.x+cos(pi+spaceship.angle),spaceship.y+sin(pi+spaceship.angle),'or','markersize',8,'MarkerFaceColor','r');
            plot(spaceship.x+2*cos(pi+spaceship.angle),spaceship.y+2*sin(pi+spaceship.angle),'oy','markersize',2,'MarkerFaceColor','y');
            
        end
        
        title(['x-velocity: ',num2str((round(spaceship.vx*100))/100),' y-velocity: ',num2str((round(spaceship.vy*100))/100)],'color','w');
        
        
    end
else
    plot(spaceship.x,spaceship.y,'*r','markersize',20)
    
    title('You kill the crew captain','color','r')
    
end
xlabel('Fire: Spacebar Turn left: <-  Turn rigth -> Restart: ENTER','color','w');
if spaceship.fuel>=0
    ylabel(['Fuel: ',num2str(spaceship.fuel),' '],'color','w','rotation',0);
else
    ylabel('Fuel: EMPTY ','color','r','rotation',0);
end
end

function keypress(varargin)
%This is the controls setup.
%I leave the main keys here even if I dont use them as remainder of names
%and possibilities.
global spaceship terrain
key = get(gcbf,'CurrentKey');
if strcmp(key,'')
elseif strcmp(key,'shift')
elseif strcmp(key,'space')
    spaceship.fire=1;
elseif strcmp(key,'leftarrow')
    spaceship.angle=spaceship.angle+pi/16;
elseif strcmp(key,'uparrow')
elseif strcmp(key,'rightarrow')
    spaceship.angle=spaceship.angle-pi/16;
elseif strcmp(key,'downarrow')
elseif strcmp(key,'return')
    %Restart the ship.
    %Define state of spaceship
    %Position
    spaceship.x=40;
    spaceship.y=40;
    %Velocity
    spaceship.vx=0;
    spaceship.vy=0;
    %Rotation
    spaceship.angle=pi/2;
    %Engine on/off
    spaceship.fire=0;
    %Fuel
    spaceship.fuel=500;
    
    %These are related to the win/lose state of the game.
    spaceship.physics=1;
    spaceship.win=0;
    spaceship.crash=0;
    
    %Restart the land
    terrain.xx=linspace(0,80,1000);
    terrain.yy=20+16*sin(0.1*(terrain.xx+10*rand())).*sin(0.4*terrain.xx+10*rand())+0.1*rand(1,1000).*sin(0.22*terrain.xx);
    terrain.wx=80*rand();
    i=min(find(min((terrain.xx-terrain.wx).^2)==(terrain.xx-terrain.wx).^2));
    terrain.wy=terrain.yy(i)+0.5;
end;
end

function keyrelease(varargin)
%This is the controls setup.
%I leave the main keys here even if I dont use them as remainder of names
%and possibilities.
global spaceship terrain
key = get(gcbf,'CurrentKey');
if strcmp(key,'')
elseif strcmp(key,'shift')
elseif strcmp(key,'space')
    spaceship.fire=0;
elseif strcmp(key,'leftarrow')    
elseif strcmp(key,'uparrow')
elseif strcmp(key,'rightarrow')  
elseif strcmp(key,'downarrow')
elseif strcmp(key,'return')   
end;
end


function check()
%This function checks if we crash the spaceship or if we win.
global spaceship  terrain
i=min(find(min(( terrain.xx-spaceship.x).^2)==(terrain.xx-spaceship.x).^2));
%This checks if we hit the surface or the boundaries.
if terrain.yy(i)>spaceship.y || spaceship.x<0 ||spaceship.x>80
    spaceship.crash=1;
    spaceship.physics=0;
end
%This checks if we land on the correct place
if ((spaceship.x-terrain.wx)^2+(spaceship.y-terrain.wy)^2)<5
    spaceship.win=1;
    spaceship.physics=0;
    spaceship.angle=pi/2;
end
end

function physics()
%This is a basic function to calculate the movement of the spaceship
global spaceship dt
%Check if engine has fuel
if spaceship.fuel>=0 && spaceship.fire==1
    spaceship.fuel=spaceship.fuel-1;
else
    
    spaceship.fire=0;
end
%First the aceleration due to the engine (massless spaceship).
ax=cos(spaceship.angle)*spaceship.fire*dt;
ay=sin(spaceship.angle)*spaceship.fire*dt;
%Then update the velocity.
g=0.4;
spaceship.vx=spaceship.vx+ax;
spaceship.vy=spaceship.vy+ay-g*dt;
%Update the position.
spaceship.x=spaceship.x+spaceship.vx*dt;
spaceship.y=spaceship.y+spaceship.vy*dt;
end

function engine_sound()
%This is to generate the sound of the enegine when it fires.
cf = 100;                  % carrier frequency (Hz)
sf = 22050;                 % sample frequency (Hz)
d = 0.1;                    % duration (s)
n = sf * d;                 % number of samples
s = (1:n) / sf;             % sound data preparation
s = sin(2 * pi * cf * s).*cos(cf*s)+0.01*rand(1,n).*cos(4*cf*s);  %Some strange noise
sound(s, sf);               % sound presentation
end

Contact us