Code covered by the BSD License  

Highlights from
Stellaria (Tech Demo) - The best MATLAB shooting game ever

image thumbnail

Stellaria (Tech Demo) - The best MATLAB shooting game ever

by

 

14 May 2011 (Updated )

If you think you have played the best MATLAB game before. Think again after you try this one.

Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

stl_StellariaMainApp()
function stl_StellariaMainApp()

clear;
%% Add source file paths
% main_name = mfilename('fullpath');
% [main_path main_file] = fileparts(main_name); 
% addpath(genpath(main_path),'-begin');

%% Declare the Global Variables
% Global Constants
global GAME_RESOLUTION
global PLAYER_CONST;
global FPS
global FRAME_DURATION
global PLAYER_ANIM
global MAX_FRAME_SKIP

% Global Variables
global CurrentFrameNo
global allowEnemyEntrance               % Whether the enemies are allowed to be added to the world


% Global Image Queues
global queueGlobalImageHandles          % The Global Image Object Queue
global numAvailGlobalImageHandles       % The number of unused image objects
global availGlobalImageHandles          % The indices of unused image objects

% Global Player Queues
global queueGlobalPlayers
global MAX_NUM_PLAYER_OBJ
global queueGlobalFriendlyFire
global MAX_NUM_IMAGE_OBJ

global usedNeutralObjects
global usedGlobalEnemies
global usedGlobalFriendlyFire

% Global Enemey Queues
global emptyEnemyStruct     % an enemy struct whose fields contain empty arrays.
% Used to reset destroyed enemies
% global enemyStructFields    % The field names for the enemy struct
global queueGlobalEnemies   % The Global Enemy Queue
global availGlobalEnemies   % The indices of unused enemy queue elements
global numAvailGlobalEnemies    % The number of unused enemie queue elements

global numAvailGlobalFriendlyFire

% global Enemy Bounding Boxes
global queueGlobalEnemyAttBoxes     % The aggressive boxes of all enemies
global queueGlobalEnemyDefBoxes     % The defensive boxes of all enemies
global indGlobalEnemyAttBoxes    % The index of global enemies an attbox represents
global indGlobalEnemyDefBoxes    % The index of global enemies an defbox represents

%
global ActivePlayers

%% Global Constants
% Main Figure and Axes
global MainFigureHdl;
global MainAxesHdl;

global MainFigureSize;
global MainAxesSize;
global MainFigureInitPos;
global MainAxesInitPos;

%% Key Names
global LeftKeyNames;
global RightKeyNames;
global UpKeyNames;
global DownKeyNames;
global FireKeyNames;
global BombKeyNames;
global PauseKeyNames;
global StartKeyNames;
global CoinKeyNames;

%% Key Status
global LeftKeyStatus;
global RightKeyStatus;
global UpKeyStatus;
global DownKeyStatus;
global FireKeyStatus;
global BombKeyStatus;
global PauseKeyStatus;
global StartKeyStatus;
global CoinKeyStatus;

global LeftKeyEffective;
global RightKeyEffective;
global UpKeyEffective;
global DownKeyEffective;
global FireKeyEffective;
global BombKeyEffective;
global PauseKeyEffective;
global StartKeyEffective;
global CoinKeyEffective;


% global bkgMusicPlayer
global thisStageTimeTable;

% Miscellaneous
global SPECIAL_FLAG
global starScrollTimer
global stageStartTime

global timer2sec
global CloseRequest
timer2sec = 2.740503272320022e+06; % 2.740503272320022e+06 per sec
CloseRequest = false;
%% --------------------- Code Starts Here -----------------------
% try
stl_initVariables();
stl_updateStarScroll;
CurrentFrameNo = 0;
currentStage = 0;
stage_table = {'stl_STAGE_TitleScreen', 'stl_STAGE_stage1', 'stl_STAGE_Credits'};
% stage_table = {'stl_STAGE_TitleScreen', 'stl_STAGE_Credits'};


%% Loop for The Title Screen 
bkgMusicPlayer = eval(stage_table{currentStage+1});
frame_updated = false;
CurrentFrameNo = 0;
% stageStartTime = GetSecs;
stageStartTime = tic;

for i = 1:MAX_NUM_PLAYER_OBJ
    set(queueGlobalPlayers(i).ImageHandle, 'Visible', 'off');
end

while 1
    if CloseRequest
        delete(MainFigureHdl);
        clear all;
        return;
    end
    loops = 0;
%     curTime = GetSecs - stageStartTime;     % Get the elapsed time since the start of the stage
    curTime = toc(stageStartTime);
    while (curTime >= (CurrentFrameNo * FRAME_DURATION) && loops < MAX_FRAME_SKIP)
        stl_collisionDetection();
        if allowEnemyEntrance
            stl_enterEnemies();
        end
        
        if CurrentFrameNo == 50
            play(bkgMusicPlayer);
        end

        stl_processNeutralObjects();
        
        stl_updateStarScroll;
        stl_UpdateObjectPos();
        
        CurrentFrameNo = CurrentFrameNo + 1;
        loops = loops + 1;
        frame_updated = true;
    end
    
    % Only redraw the frame if the a new frame has been processed
    if frame_updated
        drawnow;
        frame_updated = false;
    end
    
    % If any of the start key is pressed, then start the game
    if StartKeyEffective(2)
        ActivePlayers(1:2) = true;
        StartKeyEffective(:) = false;
        break;
    elseif StartKeyEffective(1)
        ActivePlayers(1) = true;
        ActivePlayers(2) = false;
        StartKeyEffective(:) = false;
        break;
    end

end
clear bkgMusicPlayer
currentStage = currentStage + 1;

% Delete all neutral objects before the start of the first regular stage
stl_deleteFromGlobalNeutralObjects(find(usedNeutralObjects));

%% Loop for regular Stages
while 1
    if currentStage + 1>= numel(stage_table);
        break;
    end
    bkgMusicPlayer = eval(stage_table{currentStage+1});
    
    
%     t1 = zeros(1,1000);
%     t2 = zeros(1,1000);
%     t3 = zeros(1,1000);
%     t4 = zeros(1,1000);
%     t5 = zeros(1,1000);
%     t6 = zeros(1,1000);
%     n7 = zeros(1,1000);
    frame_updated = false;
    CurrentFrameNo = 0;
%     stageStartTime = GetSecs;
    stageStartTime = tic;
    while 1
        loops = 0;
       %% Pause the Game if 'PauseKey' is Pressed
        pauseElapsedTime = 0;
        if CloseRequest
            PauseKeyEffective = PauseKeyEffective | true;
        end
        while 1
            
            if any(PauseKeyEffective)
                SPECIAL_FLAG.IS_GAME_PAUSED = ~SPECIAL_FLAG.IS_GAME_PAUSED;
                PauseKeyEffective(:) = false;
                if SPECIAL_FLAG.IS_GAME_PAUSED
                    pauseTimer = tic;
                    pauseText = text(GAME_RESOLUTION(1)./2, GAME_RESOLUTION(2)./2, ...
                        'PAUSED',...
                        'Parent', MainAxesHdl, ...
                        'Color', [1 1 1], ...
                        'FontName', 'Arial',...
                        'FontSize', GAME_RESOLUTION(2).*1/10, ...
                        'VerticalAlignment', 'middle',...
                        'HorizontalAlignment', 'center');
                else
                    delete(pauseText);
                    pauseElapsedTime = toc(pauseTimer);
                    starScrollTimer = tic;
                end
            end
            if ~SPECIAL_FLAG.IS_GAME_PAUSED
                stageStartTime = uint64(double(stageStartTime) + pauseElapsedTime.*timer2sec);                
                break;
            else
                drawnow;
                if CloseRequest
                    BName = questdlg('Are you sure you want to quit?','Stellaria','Yes','No', 'No');
                    if strcmp(BName,'Yes')
                        clear bkgMusicPlayer
                        stl_deleteFromGlobalNeutralObjects(find(usedNeutralObjects));
                        stl_deleteFromGlobalEnemies(find(usedGlobalEnemies));
                        stl_deleteFromGlobalFriendlyFire(find(usedGlobalFriendlyFire));
                        delete(MainFigureHdl);
                        clear all
                        return;
                    else
                        CloseRequest = false;
                        PauseKeyEffective = PauseKeyEffective | true;
                    end
                end
            end
        end
        
       %%
%         curTime = GetSecs - stageStartTime;     % Get the elapsed time so far
        curTime = toc(stageStartTime);
%         if CurrentFrameNo >= 999
%             %         a = 3;
% %             break;
%         end
        
        while (curTime > (CurrentFrameNo * FRAME_DURATION) && loops < MAX_FRAME_SKIP)
            
           %% The stage is over when there are no more enemies to be added
           %% and there are no existing enemies on the screen
            if isempty(thisStageTimeTable) && nnz(usedGlobalEnemies) == 0
                SPECIAL_FLAG.STAGE_OVER = true;
            else
                SPECIAL_FLAG.STAGE_OVER = false;
            end
            
            stl_collisionDetection();
            if allowEnemyEntrance
                stl_enterEnemies();
            end
%             startt = GetSecs;
            if CurrentFrameNo == 50
                play(bkgMusicPlayer);
            end
            
            % Add 'Impromptu' enemies, e.g. bullets, powerups and those objects
            % which do not enter the stage at a fixed time.
            stl_enterImpromptuEnemies();
            
%             t1(mod(CurrentFrameNo+1,1000)+1) = GetSecs - startt; startt = GetSecs;
            
            
            stl_processPlayer();
%             t2(mod(CurrentFrameNo+1,1000)+1)  = GetSecs - startt; startt = GetSecs;
            
            
            stl_processEnemies();
%             t3(mod(CurrentFrameNo+1,1000)+1)  = GetSecs - startt; startt = GetSecs;
            %         if any(usedNeutralObjects)
            stl_processNeutralObjects();
            %         end
%             t4(mod(CurrentFrameNo+1,1000)+1)  = GetSecs - startt; startt = GetSecs;
            stl_updateStarScroll;
            stl_UpdateObjectPos();
            
%             t5(mod(CurrentFrameNo+1,1000)+1)  = GetSecs - startt; startt = GetSecs;
            CurrentFrameNo = CurrentFrameNo + 1;
            loops = loops + 1;
            frame_updated = true;
        end
        
        %     stl_updateStarScroll;
        %     if frame_updated
        %         stl_UpdateObjectPos();
        %         frame_updated = false;
        %     end
%         startt = GetSecs;
        if frame_updated
            drawnow;
            frame_updated = false;
            
        end
%         t6(mod(CurrentFrameNo,1000)+1)  = GetSecs - startt;
%         n7(mod(CurrentFrameNo,1000)+1) = numAvailGlobalImageHandles;
        
        % If the STAGE is already over
        if SPECIAL_FLAG.STAGE_OVER

            stageOverFlag = [queueGlobalPlayers(1).Pos(2)<-50 queueGlobalPlayers(2).Pos(2)<-50];
            if all(stageOverFlag(ActivePlayers))
                break;
            end

        end
    end
    clear bkgMusicPlayer
    currentStage = currentStage + 1;
    stl_deleteFromGlobalNeutralObjects(find(usedNeutralObjects));
    stl_deleteFromGlobalEnemies(find(usedGlobalEnemies));
    stl_deleteFromGlobalFriendlyFire(find(usedGlobalFriendlyFire))
    SPECIAL_FLAG.STAGE_OVER = false;
    [queueGlobalPlayers.BeingBorn] = deal(true);
    for i = 1:MAX_NUM_PLAYER_OBJ
        queueGlobalPlayers(i).LivesLeft = queueGlobalPlayers(i).LivesLeft+1;
    end
end

%% Loop for showing the Credits
bkgMusicPlayer = eval(stage_table{currentStage+1});
frame_updated = false;
CurrentFrameNo = 0;
% stageStartTime = GetSecs;
stageStartTime = tic;

for i = 1:MAX_NUM_PLAYER_OBJ
    set(queueGlobalPlayers(i).ImageHandle, 'Visible', 'off');
end

while 1
    loops = 0;
    if CloseRequest
        delete(MainFigureHdl);
        clear all;
        return;
    end
    
%     curTime = GetSecs - stageStartTime;     % Get the elapsed time since the start of the stage
    curTime = toc(stageStartTime);
    while (curTime >= (CurrentFrameNo * FRAME_DURATION) && loops < MAX_FRAME_SKIP)
        stl_collisionDetection();
        if allowEnemyEntrance
            stl_enterEnemies();
        end
        
        if CurrentFrameNo == 50
            play(bkgMusicPlayer);
        end

        stl_processNeutralObjects();
        
        stl_updateStarScroll;
        stl_UpdateObjectPos();
        
        CurrentFrameNo = CurrentFrameNo + 1;
        loops = loops + 1;
        frame_updated = true;
    end
    
    % Only redraw the frame if the a new frame has been process
    if frame_updated
        drawnow;
        frame_updated = false;
    end
    
    % If any of the start key is pressed, then start the real game
    if StartKeyEffective(2)
        ActivePlayers(1:2) = true;
        StartKeyEffective(:) = false;
        break;
    elseif StartKeyEffective(1)
        ActivePlayers(1) = true;
        ActivePlayers(2) = false;
        StartKeyEffective(:) = false;
        break;
    end

end
clear bkgMusicPlayer
% catch ME
%     a = 3;
% end
close all;
% figure(1);plot(t1);
% figure(2);plot(t2);
% figure(3);plot(t3);
% figure(4);plot(t4);
% figure(5);plot(t5);
% figure(6);plot(t6);
% figure(7);plot(n7);

Contact us