First commit

master
Howard T 2017-03-28 14:52:59 +08:00
commit 406cd63527
4 changed files with 1034 additions and 0 deletions

BIN
mazemap.mat 100644

Binary file not shown.

90
snek_editor_help.m 100644
View File

@ -0,0 +1,90 @@
function snek_editor_help()
scrsz = get(0,'ScreenSize');
helpwin = figure('ToolBar','none','Name','SNEK Editor Help',...
'NumberTitle','off','MenuBar','none',...
'Resize','off','Visible','off','Color',[170 255 211]/255,...
'Position',[scrsz(3)/8,scrsz(4)/8,min(scrsz(3:4)/1.2),min(scrsz(3:4)/1.5)]);
tgroup = uitabgroup('Parent', helpwin);
tab1 = uitab('Parent', tgroup, 'Title', 'Introduction');
tab1_text = uicontrol('Style','text','Units','Normalized','Position',[0 0 1 1],'FontSize',10,'Parent',tab1);
tab2 = uitab('Parent', tgroup, 'Title', 'Map Packs');
tab2_text = uicontrol('Style','text','Units','Normalized','Position',[0 0 1 1],'FontSize',10,'Parent',tab2);
tab3 = uitab('Parent', tgroup, 'Title', 'Backups and Rolling Back');
tab3_text = uicontrol('Style','text','Units','Normalized','Position',[0 0 1 1],'FontSize',10,'Parent',tab3);
tab4 = uitab('Parent', tgroup, 'Title', 'Map Listings');
tab4_text = uicontrol('Style','text','Units','Normalized','Position',[0 0 1 1],'FontSize',10,'Parent',tab4);
tab5 = uitab('Parent', tgroup, 'Title', 'Map Editing');
tab5_text = uicontrol('Style','text','Units','Normalized','Position',[0 0 1 1],'FontSize',10,'Parent',tab5);
tab6 = uitab('Parent', tgroup, 'Title', 'Player Editing');
tab6_text = uicontrol('Style','text','Units','Normalized','Position',[0 0 1 1],'FontSize',10,'Parent',tab6);
intro_text = { 'This editor and help is created by EN YI','',...
'Hello! Welcome to the SNEK map editor!',...
'This editor allows you to create maps for the snake game for MATLAB created by me.',...
'You can use the tabs to navigate to the section you want help on.','',...
'By having the editor, you also have the source code yourself.',...
'So, you may modify the code to your heart delights',...
'Just remember to credit me for the original code','',...
'Please report any problems with the editor to me',...
'Please also state the method to replicate the error',...
'Any suggestions/improvements are also welcomed, unless otherwise stated ','',...
'You can contact me by emailing to randomsity1@gmail.com',...
'Happy editing!','','',...
'Credits: ',...
'Mathworks for creating MATLAB',...
'and Google for most of my MATLAB problems'};
map_pack_text = { 'By default, you should have a file called "mazemap.mat".',...
'That is the default file the snake game will load.','',...
'When first opened, the editor will look empty as no file is loaded.',...
'Press the "Change Map Pack" on the top to load a map pack.',...
'When a pack is loaded, two extra files is created.',...
'backup_<filename> and old_<filemap>',...
'Make sure you have the files in the same directory as the editor','',...
'You may also press on the "New Map Pack" on the top to create a new pack pack',...
'A list will show you names of other mat files so you don''t replace them when creating a new file',...
'Enter the new file name and press okay.',...
'On the top right corner is the pack name. You can rename this anytime.',...
'The new name will be used the next time you save.'};
map_file_text = { 'There is two files when you load a file:',...
'backup_<filename> and old_<filemap>',...
'Both will allow you to roll back changes you made to your map pack','',...
'backup_<filename> will revert changes to the last time you saved',...
'You can do so by pressing the "Reset changes" button at the bootom left corner','',...
'old_<filemap> will revert changes to the moment you opened the editor',...
'You have to load this yourself with the "Change Map Pack" button','',...
'Keep these in mind when trying to reset any changes'};
map_list_text = { 'Below the pack name shows all the maps contained within the pack.','',...
'Click on one of the map name to display the map','',...
'Press on the UP and DOWN buttons to sort the order of the map up and down respectively','',...
'Press on the "New" button to add a new map at the end of the list','',...
'Press on the "Delete" button to delete the selected map','',...
'Press on the "Save" button to save ALL changes in the map pack','',...
'You may edit the map name, which is below the "Save button"','',...
'Changes are applied once you click out of the box'};
map_edit_text = { 'The current map is displayed next to the map list',...
'You can change the map name, width, and height in their respective boxes','',...
'Left click to add a tile. Right Click to remove a tile','',...
'Middle click to add a "nospawn" tile, where fruits cannot spawn in',...
'They look slightly less black','',...
'You can drag along the map to continuously add/remove tile',...
'You cannot draw tiles over the snake','',...
'You can also resize the map, by edit its width and height',...
'Note that any tiles outside of the map wil be removed when resizing.','',...
'Below the width and height boxes shows the coordinates of the mouse on the map.'};
player_edit_text = {'The speed slider changes the speed of the snake in this map, from 1 to 25','',...
'Click on the "Redefine player position" button to edit the snake starting position',...
'This works just like adding tiles, but you must make sure the snake is continuous.',...
'The red tiles indicate the snake''s head','',...
'Click on the "Redefine player position" button again to stop edit the player position','',...
'The "Red","Green","Blue" sliders adjust the colour of the snake''s body','',...
'Click on the "Reset Colour" to restore the snake to its default colour','',...
'Click on the "Reset Speed" to reset the speed of the snake',''};
set(tab1_text,'String',intro_text);
set(tab2_text,'String',map_pack_text);
set(tab3_text,'String',map_file_text);
set(tab4_text,'String',map_list_text);
set(tab5_text,'String',map_edit_text);
set(tab6_text,'String',player_edit_text);
set(helpwin,'Visible','on');
end

556
snek_editor_viper.m 100644
View File

@ -0,0 +1,556 @@
%% Information
% Original author: En Yi
% A map editor for the snake game created by the same author
% Have fun!
% Anyone can modify it, just need to give credits to the original author
function snek_editor_viper()
%% Define variables
file_name = '';map = {};map_name = {};speed = 0;
num_of_map = 0;current_map = 1;selected_map = [];
player_body = {};selected_body=[];colours = {};selected_colour = [];
prev_X = 0;prev_Y = 0;edit_enable=0;
default_colours = [0.7 0.2 0.5];
%% Prepare the window
%Create the window
scrsz = get(0,'ScreenSize');
min_dim = min(scrsz(3:4)/1.2);
win = figure('ToolBar',...
'none','Name','SNEK Map Editor','NumberTitle','off','MenuBar','none',...
'Resize','off','Visible','off','Color',[170 255 211]/255,...
'Position',[scrsz(3)/8,scrsz(4)/8,min_dim,min_dim],...
'WindowButtonMotionFcn',@display_mouse_pos);
%Prepare the block units
blk = 33;
blocks = min_dim/blk;
%% Prepare the UI components
%Create the map list
map_listbox = uicontrol('Style','listbox','Position',[1,19,6,11]*blocks,...
'String',map_name,'Max',1,'Min',1,'Callback',@show_map);
%Create the map grid
map_panel = uipanel('Position',[8,7,23,23]/blk);
map_axes = axes('Parent',map_panel);
%UI to handle map packs
mappack_name_text = uicontrol('Style','text','Position',[1,31.5,7,1]*blocks,...
'String','Pack Name');
mappack_name_edit = uicontrol('Style','edit','Position',[1,30.5,7,1]*blocks);
change_mappack_button = uicontrol('Style','pushbutton','Position',[9,31,6,1.5]*blocks,...
'String','Change Map Pack','Callback',@change_mappack);
create_mappack_button = uicontrol('Style','pushbutton','Position',[16,31,6,1.5]*blocks,...
'String','New Map Pack','Callback',@new_mappack);
%Buttons to sort the map order
sort_up_button = uicontrol('Style','pushbutton','Position',[1,17,2.5,2]*blocks,...
'String','UP','Callback',{@sort_map,-1});
sort_down_button = uicontrol('Style','pushbutton','Position',[4,17,2.5,2]*blocks,...
'String','DOWN','Callback',{@sort_map,1});
%Buttons to create and delete maps, and save the current changes to the pack
new_button = uicontrol('Style','pushbutton','Position',[1,15,4,2]*blocks,...
'String','New','Callback',@new_map);
delete_button = uicontrol('Style','pushbutton','Position',[1,13,4,2]*blocks,...
'String','Delete','Callback',@delete_map);
save_button = uicontrol('Style','pushbutton','Position',[1,11,4,2]*blocks,...
'String','Save','Callback',@save_map,'Interruptible','off','BusyAction','cancel');
%UI to change the map name
map_name_text = uicontrol('Style','text','Position',[1,9,5,1]*blocks,...
'String','Map Name');
map_name_edit = uicontrol('Style','edit','Position',[1,8,5,1]*blocks,...
'Callback',@edit_map_name);
%UI to change the map size
map_width_text = uicontrol('Style','text','Position',[1,6,2.5,1]*blocks,...
'String','Width');
map_width_edit = uicontrol('Style','edit','Position',[4,6,2,1]*blocks,...
'Callback',@resize_map);
map_width_text = uicontrol('Style','text','Position',[1,5,2.5,1]*blocks,...
'String','Height');
map_height_edit = uicontrol('Style','edit','Position',[4,5,2,1]*blocks,...
'Callback',@resize_map);
%UI to reset the map changes
reset_button = uicontrol('Style','pushbutton','Position',[1,1,5,2]*blocks,...
'String','Reset changes','Callback',@reset_changes);
%UI to change the speed of the game
speed_text = uicontrol('Style','text','Position',[7,5.5,2.5,1]*blocks,...
'String','Speed');
speed_slider = uicontrol('Style','slider','Position',[10,5.5,9,1]*blocks,'value',12.5,...
'String','Speed','Callback',@change_speed,'Min',1,'Max',25,'SliderStep',[0.1 1]/24);
speed_value_text = uicontrol('Style','text','Position',[19,5.5,2.5,1]*blocks,...
'HorizontalAlignment','center');
%UI for the editor manual
help_button = uicontrol('Style','pushbutton','Position',[28,1,5,2]*blocks,...
'String','Need Help?','Callback',@open_manual);
%UI for displaying the version
version_text = uicontrol('Style','text','Position',[26.5,-1,7,2]*blocks,...
'String','V1.1 Made by En Yi','BackgroundColor',[170 255 211]/255);
%UI for displaying the mouse position
mouse_xpos_text = uicontrol('Style','text','Position',[1,3.5,2.5,1]*blocks,...
'HorizontalAlignment','center');
mouse_ypos_text = uicontrol('Style','text','Position',[4,3.5,2.5,1]*blocks,...
'HorizontalAlignment','center');
redefine_player_toggle = uicontrol('Style','togglebutton','Position',[22,5.5,8,1.5]*blocks,...
'String','Redefine player position');
%UI for snake colour
colour_red_text = uicontrol('Style','text','Position',[7,4,2.5,1]*blocks,...
'String','Red');
colour_red_slider = uicontrol('Style','slider','Position',[10,4,9,1]*blocks,...
'String','Speed','Callback',@change_colour,'Min',0,'Max',1,'SliderStep',[0.01 0.1]);
red_value_text = uicontrol('Style','text','Position',[19,4,2.5,1]*blocks,...
'HorizontalAlignment','center');
colour_green_text = uicontrol('Style','text','Position',[7,2.5,2.5,1]*blocks,...
'String','Green');
colour_green_slider = uicontrol('Style','slider','Position',[10,2.5,9,1]*blocks,...
'String','Speed','Callback',@change_colour,'Min',0,'Max',1,'SliderStep',[0.01 0.1]);
green_value_text = uicontrol('Style','text','Position',[19,2.5,2.5,1]*blocks,...
'HorizontalAlignment','center');
colour_blue_text = uicontrol('Style','text','Position',[7,1,2.5,1]*blocks,...
'String','Blue');
colour_blue_slider = uicontrol('Style','slider','Position',[10,1,9,1]*blocks,...
'String','Speed','Callback',@change_colour,'Min',0,'Max',1,'SliderStep',[0.01 0.1]);
blue_value_text = uicontrol('Style','text','Position',[19,1,2.5,1]*blocks,...
'HorizontalAlignment','center');
%UI to reset values to default
colour_reset_button = uicontrol('Style','pushbutton','Position',[22,3,5,2]*blocks,...
'String','Reset Colours','Callback',@reset_colours);
reset_speed_button = uicontrol('Style','pushbutton','Position',[22,1,5,2]*blocks,...
'String','Reset Speed','Callback',@reset_speed);
%Disable UI until user loads a map pack
disenable(0);
set(change_mappack_button,'Enable','On');
set(create_mappack_button,'Enable','On');
set(help_button,'Enable','On');
set(win,'Visible','on');
%% Callback functions
%Function to display a map and its info
function show_map(src,~)
%Store the current map chagnes
map{current_map} = selected_map;
player_body{current_map} = selected_body;
colours{current_map} = selected_colour;
%Get the selected map info
map_n = get(src,'Value');
selected_map = map{map_n};
selected_body = player_body{map_n};
selected_colour = colours{map_n};
current_map = map_n;
%Display everything
refresh_map();
update_maplist();
update_map_info();
end
%Function to start the dragging function in editting
function drag_edit_enable(~,~)
if (edit_enable==0)
%Store the current callback of the figure
props.WindowButtonMotionFcn = get(win,'WindowButtonMotionFcn');
props.WindowButtonUpFcn = get(win,'WindowButtonUpFcn');
setappdata(win,'TestGuiCallbacks',props);
%Set the dragging edit callback and disable drag callback
set(win,'WindowButtonMotionFcn',@edit_map);
set(win,'WindowButtonUpFcn',@drag_edit_disable);
%Set the editting variables
prev_X = 0;prev_Y = 0;edit_enable=1;
%Edit the current tile
edit_map();
end
end
%Function to stop the dragging function in editting
function drag_edit_disable(~,~)
if (edit_enable==1)
%Reset the original callbacks of the figure
props = getappdata(win,'TestGuiCallbacks');
set(win,props);
%Set the editting variables
prev_X = 0;prev_Y = 0;edit_enable=0;
end
end
%Function to edit the tile of a map
function edit_map(~,~)
%Check if the user is defining player position
player_redf = get(redefine_player_toggle,'value');
%Check which mouse button is pressed
if(~player_redf)
edit_type = 1;
switch(get(win,'selectiontype'))
case 'normal'
edit_type = 1;%Add tile
case 'alt'
edit_type = 0;%Remove tile
case 'extend'
edit_type = 0.1;%Add nospawn tile
end
end
%Get the mouse position
[X,Y] = display_mouse_pos();
%Only edit a tile if the user move away from the current tile
%and stay within the map
map_sz = size(selected_map);
if (X>0 && X<=map_sz(2) && Y>0 && Y<=map_sz(1) && (X ~= prev_X || Y ~= prev_Y))
%Map tile editing
if(~player_redf)
if ~(any((Y == selected_body(2,:)) & (X==selected_body(1,:))))
selected_map(Y,X,:) = edit_type;
end
else
%Player position editing
%Only add to player if it is continuous,
%otherwise reset the player position
if (selected_map(Y,X)~=1)
if (( abs(X- selected_body(1,1))+abs(Y- selected_body(2,1)) == 1)&&...
~any(X==selected_body(1,:) & Y==selected_body(2,:)) )
selected_body = [[X;Y] selected_body];
else
selected_body = [X;Y];
end
end
end
end
%Store the previous mouse position
prev_X = X;prev_Y = Y;
refresh_map();
end
%Function to add a new map
function new_map(~,~)
%Create the new map+infos
new_mat = zeros(30,30,3);
new_body = [15 14 13; 15 15 15];
new_colour = default_colours;
%Append the new map+infos
map = [map new_mat];
num_of_map = length(map);
map_name = [map_name sprintf('map_%d',num_of_map)];
speed = [speed 12.5];
player_body = [player_body new_body];
colours = [colours new_colour];
%Set to display the new map
selected_map = new_mat;
selected_body = new_body;
selected_colour = new_colour;
current_map = num_of_map;
set(map_listbox,'value',num_of_map);
refresh_map();
update_maplist();
update_map_info();
end
%Function to delete a map
function delete_map(~,~)
%Only delete if there is more than one map
if(num_of_map ~=1)
map_num = get(map_listbox,'Value');
map = [map(1:map_num-1) map(map_num+1:end)];
map_name = [map_name(1:map_num-1) map_name(map_num+1:end)];
speed = [speed(1:map_num-1) speed(map_num+1:end)];
player_body = [player_body(1:map_num-1) player_body(map_num+1:end)];
colours = [colours(1:map_num-1) colours(map_num+1:end)];
num_of_map = length(map);
%Shift the map if the deleted map is not the first one
if (map_num>num_of_map)
map_num = map_num - 1;
end
set(map_listbox,'Value',map_num);
selected_map = map{map_num};
selected_body = player_body{map_num};
selected_colour = colours{map_num};
current_map = map_num;
refresh_map();
update_maplist();
update_map_info();
end
end
%Function to save all the changes
function save_map(~,~)
try
file_name = get(mappack_name_edit,'String');
map{current_map} = selected_map;
player_body{current_map} = selected_body;
colours{current_map} = selected_colour;
save(file_name,'map','map_name','speed','player_body','colours');
save(['backup_' file_name],'map','map_name','speed','player_body','colours');
catch
savebox = errordlg('Error occured while saving','modal');
uiwait(savebox);
return
end
savebox = msgbox('Save Complete','modal');
uiwait(savebox);
end
%Function to move a map up or down
function sort_map(~,~,dir)
map_num = get(map_listbox,'Value');
%Move down the map, if the map is not the last map
if (dir==1)
if (map_num ~= num_of_map)
map = move_list(map,map_num,1);
map_name = move_list(map_name,map_num,1);
speed = move_list(speed,map_num,1);
player_body = move_list(player_body,map_num,1);
colours = move_list(colours,map_num,1);
current_map = map_num+1;
set(map_listbox,'Value',current_map);
end
%Move up the map, if it is not the first
elseif (dir == -1)
if (map_num ~= 1)
map = move_list(map,map_num,-1);
map_name = move_list(map_name,map_num,-1);
speed = move_list(speed,map_num,-1);
player_body = move_list(player_body,map_num,-1);
colours = move_list(colours,map_num,-1);
current_map = map_num-1;
set(map_listbox,'Value',current_map);
end
end
%Update everything
refresh_map();
update_maplist();
end
%Function to change the map name
function edit_map_name(src,~)
map_name{current_map} = get(src,'String');
update_maplist();
end
%Function change the speed of the snake
function change_speed(src,~)
spd_val = get(src,'Value');
spd_val = round(spd_val*10)/10;
speed(current_map) = spd_val;
update_map_info();
end
%Function change the size of the map
function resize_map(~,~)
%Get the new dimension
new_width = str2double(get(map_width_edit,'String'));
new_height = str2double(get(map_height_edit,'String'));
map_sz = size(selected_map);
%Do the width first
%If it is enlarging, append the extra columns
if (new_width>map_sz(2))
selected_map = [selected_map zeros(map_sz(1),new_width-map_sz(2),3)];
else
%If it is shrinking, delete the extra columns
selected_map = selected_map(:,1:new_width,:);
end
%Redo for height
map_sz = size(selected_map);
if (new_height>map_sz(1))
selected_map = [selected_map; zeros(new_height-map_sz(1),map_sz(2),3)];
else
selected_map = selected_map(1:new_height,:,:);
end
map_sz = size(selected_map);
selected_body = floor([map_sz(2);map_sz(1)]/2+1);
refresh_map();
end
%Function to reset the changes
function reset_changes(~,~)
load_map_pack(['backup_' file_name])
refresh_map();
update_maplist();
update_map_info();
end
%Function to open the manual
function open_manual(~,~)
snek_editor_help();
end
%Function to obtain and display the mouse position
function [X,Y] = display_mouse_pos(~,~)
map_sz = size(selected_map);
mpos = get(map_axes,'CurrentPoint');
X = round(mpos(1,1));
Y = round(mpos(1,2));
if (X>0 && X<=map_sz(2) && Y>0 && Y<=map_sz(1))
set(mouse_xpos_text,'String',num2str(X));
set(mouse_ypos_text,'String',num2str(Y));
end
end
%Function to change the colour of the snake body
function change_colour(~,~)
new_colour(1) = get(colour_red_slider,'value');
new_colour(2) = get(colour_green_slider,'value');
new_colour(3) = get(colour_blue_slider,'value');
selected_colour = round(new_colour*100)/100;
refresh_map();
update_map_info();
end
%Function to reset the colours
function reset_colours(~,~)
selected_colour = default_colours;
refresh_map();
update_map_info();
end
%Function to reset the speed
function reset_speed(~,~)
speed(current_map) = 12.5;
refresh_map();
update_map_info();
end
%% Non Callback functions
%Function to refresh the display
function refresh_map()
map_sz = size(selected_map);
snake_pos = zeros(map_sz);
if ~isempty(selected_body)
snake_pos(selected_body(2,1),selected_body(1,1),1) = 1;
for i = 2:length(selected_body(1,:))
snake_pos(selected_body(2,i),selected_body(1,i),:) = selected_colour;
end
end
image(selected_map+snake_pos,'Parent',map_axes,'PickableParts','none');
set(map_axes,'PickableParts','all','ButtonDownFcn',@drag_edit_enable);
set(map_axes,'Xcolor',[1 1 1],'xtick',(1:1:map_sz(2))+0.5,'XTickLabel',[]);
set(map_axes,'Ycolor',[1 1 1],'ytick',(1:1:map_sz(1))+0.5,'YTickLabel',[]);
newsize = [0 0 map_sz(2) map_sz(1)]/max(map_sz(1:2));
newsize = newsize+[0.5-newsize(3:4)/2 0 0];
set(map_axes,'Position',newsize);
grid on;
end
%Function to update the map list
function update_maplist()
set(map_listbox,'String',map_name,'Value',current_map);
end
%Function to update the UI to display the map info
function update_map_info()
set(map_name_edit,'String',map_name{current_map});
map_sz = size(map{current_map});
set(map_width_edit,'String',map_sz(2));
set(map_height_edit,'String',map_sz(1));
set(speed_slider,'Value',speed(current_map));
set(speed_value_text,'String',num2str(speed(current_map)));
set(colour_red_slider,'value',selected_colour(1));
set(red_value_text,'String',num2str(selected_colour(1)));
set(colour_green_slider,'value',selected_colour(2));
set(green_value_text,'String',num2str(selected_colour(2)));
set(colour_blue_slider,'value',selected_colour(3));
set(blue_value_text,'String',num2str(selected_colour(3)));
end
%Function to load a map pack
function load_map_pack(fname)
try
mzmp = load(fname);
catch
loadbox = errordlg('File might not exist within the directory','modal');
uiwait(loadbox);
return
end
try
map = mzmp.map;
map_name = mzmp.map_name;
speed = mzmp.speed;
player_body = mzmp.player_body;
colours = mzmp.colours;
num_of_map = length(map);
current_map = 1;
selected_map = map{current_map};
selected_body = player_body{current_map};
selected_colour = colours{current_map};
file_name = strrep(fname,'old_','');
file_name = strrep(file_name,'backup_','');
save(['backup_' file_name],'map','map_name','speed','player_body','colours');
save(['old_' file_name],'map','map_name','speed','player_body','colours');
set(mappack_name_edit,'String',file_name);
catch
loadbox = errordlg('File is corrupted','modal');
uiwait(loadbox);
return
end
disenable(1);
end
%Function to move a item in a list
function[list] = move_list(list,val,increment)
temp_list = list(val+increment);
list(val+increment) = list(val);
list(val) = temp_list;
end
%Function to enable/disable UIs
function disenable(type)
if (type == 0)
disabling = findobj(win,'Parent',win,'-not','Type','uipanel');
set(disabling,'Enable','Off');
else
enabling = findobj(win,'Parent',win,'-not','Type','uipanel');
set(enabling,'Enable','On');
end
end
%% Functions involving dialog boxes
function new_mappack(~,~)
winpos = get(win,'Position');
new_filename = 0;file_confirm = 0;
newfile = dialog('Name','Create a Map Pack','Position',[winpos(1:2)+winpos(3:4)/4 winpos(3:4)/1.5]);
matfiles = what;
matfiles = matfiles.mat;
uicontrol('Style','text','Units','normalized',...
'Position',[0.05 0.9 0.4 0.05],'String','Available files')
uicontrol('Style','listbox','Units','normalized',...
'Position',[0.1 0.3 0.7 0.6],...
'String',matfiles);
uicontrol('Style','text','Units','normalized',...
'Position',[0.05 0.15 0.3 0.1],...
'String','File Name');
new_filename_edit = uicontrol('Style','edit','Units','normalized',...
'Position',[0.3 0.175 0.6 0.075]...
);
uicontrol('Style','pushbutton','Units','normalized',...
'Position',[0.1 0.05 0.3 0.1],...
'String','Okay','Callback',@confirm_file);
uicontrol('Style','pushbutton','Units','normalized',...
'Position',[0.6 0.05 0.3 0.1],...
'String','Cancel','Callback',@cancel_file);
function confirm_file(~,~)
fname = get(new_filename_edit,'String');
if(isempty(fname));
return
end
new_filename = fname;
file_confirm = 1;
close(newfile);
end
function cancel_file(~,~)
close(newfile);
end
uiwait(newfile);
if(file_confirm)
map = {};map_name = {};speed = [];player_body = {};colours = {};
new_map();new_map();new_map();
current_map =1;
selected_map = map{current_map};
selected_body = player_body{current_map};
save(new_filename,'map','map_name','speed','player_body','colours');
load_map_pack(new_filename);
refresh_map();
update_maplist();
update_map_info();
end
end
function change_mappack(~,~)
winpos = get(win,'Position');
change_filename = 0;change_confirm = 0;
changefile = dialog('Name','Select a Map Pack','Position',[winpos(1:2)+winpos(3:4)/4 winpos(3:4)/1.5]);
matfiles = what;
matfiles = matfiles.mat;
file_listbox = uicontrol('Style','listbox','Units','normalized',...
'Position',[0.1 0.1 0.5 0.85],...
'String',matfiles);
uicontrol('Style','pushbutton','Units','normalized',...
'Position',[0.7 0.7 0.2 0.2],...
'String','Okay','Callback',@confirm_change);
uicontrol('Style','pushbutton','Units','normalized',...
'Position',[0.7 0.5 0.2 0.2],...
'String','Cancel','Callback',@cancel_change);
function confirm_change(~,~)
fnum = get(file_listbox,'value');
change_filename = matfiles{fnum};
change_filename = strrep(change_filename,'.mat','');
change_confirm = 1;
close(changefile);
end
function cancel_change(~,~)
close(changefile);
end
uiwait(changefile);
if(change_confirm)
load_map_pack(change_filename);
refresh_map();
update_maplist();
update_map_info();
end
end
end

388
snek_final.m 100644
View File

@ -0,0 +1,388 @@
%% Information
% Original author: En Yi
% A snake game on MATLAB, very self-explanatory
% Have fun!
% Anyone can modify it, just need to give credits to the original author
function snek_final()
%% Creating the game window
clc;clear;
%Default Constants
default_updatetime = 0.08;
default_ftsize = 10;
%Create the update timer, used for continuously updating the game screen
update_t = timer('ExecutionMode','fixedSpacing','Period',default_updatetime,'TimerFcn',@update_screen);
%Create the window
scrsz = get(0,'ScreenSize');
start_dim = min(scrsz(3)/1.5,scrsz(4)/1.5);%Used for rescaling
win = figure('KeyPressFcn',@key_check,'DeleteFcn',@delete_t,'ToolBar',...
'none','Name','SNEK','NumberTitle','off','MenuBar','none',...
'Resize','off','Visible','off','Color',[170 255 211]/255,...
'Position',[[scrsz(3),scrsz(4)]/4.5 start_dim start_dim]);
%For displaying instructions and score
load_map_button = uicontrol('Style','pushbutton','Units','Normalized',...
'Position',[0.01 0.01 0.2 0.08],'FontSize',default_ftsize,...
'Callback',@select_mappack,'String','Change Pack');
console_text = uicontrol('Style','text','Units','Normalized',...
'Position',[0.25 0.01 0.7 0.08],'FontSize',default_ftsize);
%Just to display the version and author
uicontrol('Style','text','Units','Normalized','Position',[24,28,6,2]/30,...
'String','V1.0 Made by En Yi','BackgroundColor',[170 255 211]/255);
%Create the axes for drawing the game
disp_axes = axes('Parent',win);
%graze = 0;
%% Load the map levels and define game variables
%Prepare the map
width = 30;height = 30;
map_number = 0;n_of_maps = 0;
maze_map = {};map_name = {};speed = [];map = zeros(width,height,3);
start_body={};player_body = [];player_len = 1;move_dir = 2;
body_colour = {};selected_colour = [];fruit_colour = [0.5 0.5 0];
load_map_pack('mazemap')
%Define the fruit fruit_values+bonus and player score
fruit_value = 0;
score = 0;
max_value = 60;
fruit_x = -1;fruit_y = -1;
%Create the sounds for collecting a fruit and losing the game
Fs = 10000;
t = 0:1/Fs:.02;
y = sin(2*pi*4000*t);
beep = audioplayer(y, Fs);
t = 0:1/Fs:0.1;
x = sawtooth(2*pi*60*t);
x = [x zeros(1,5) x];
gover = audioplayer(x, Fs);
%Define the variable to check whether the player is playing the game
game_on = 0;
%Update the screen and display controls
update_screen();
set(win,'Visible','on')
set(console_text,'String',{'WASD or Arrows key to select map','Space to start'});
%% Callback functions
%Function to update the game screen
function update_screen(~,~)
scr_mat = map; %Put in the current map
if(game_on ==1) %If the player is playing
isdead = move(scr_mat); %Move the player and check whether the player is dead
if(isdead) %If so
stop(update_t); %Stop continuously updating the screen
set(console_text,'String',{'Game Over. Press R to restart.',...
sprintf('Final Score : %d\n',floor(score/10))} );
play(gover);
return %Stop the game
end
end
%Put in the player body after updating
body_sz = size(player_body);
scr_mat(player_body(2,1),player_body(1,1),1) = 1;
for n=2:body_sz(2)
scr_mat(player_body(2,n),player_body(1,n),:) = selected_colour;
end
%Spawn the fruit if it is collected
if(fruit_x == -1)
scr_mat = spawn_fruit(scr_mat);
fruit_value = max_value; %Set the fruit fruit_values
end
%Put in the fruit
scr_mat(fruit_y,fruit_x,:) = fruit_colour;
%Set focus on the game window
figure(win);
%Draw the game screen
image(scr_mat,'Parent',disp_axes);
set(disp_axes,'XTickLabel',[],'YTickLabel',[]);
if (map_number>0)
title(map_name{map_number});
else
title('Open');
end
if(game_on ==0) %If the player is not playing
%Readjust the window screen to fit the aspect ratio of the level
current_winpos = get(win,'Position');
topright = current_winpos(2)+current_winpos(4);
new_winpos = [0 0 width height]/max([0 0 width height])...
*start_dim;
new_winpos = new_winpos+[current_winpos(1) topright-new_winpos(4) 0 0];
set(win,'Position',new_winpos);
end
end
%Function to check the key presses
function key_check(~,evtdata)
%disp(evtdata.Key);
if(game_on == 1)
%When the game is running
%Direction keys change the direction of the snake
%The inputs are recorded up to 3 key presses for updating
n = length(move_dir)+1;
if (n<4)
if (move_dir(end)~=2 && move_dir(end)~=1)
switch(evtdata.Key)
case 'leftarrow'
move_dir(n) = 1;
case 'rightarrow'
move_dir(n) = 2;
case 'a'
move_dir(n) = 1;
case 'd'
move_dir(n) = 2;
end
elseif (move_dir(end)~=3 && move_dir(end)~=4)
switch(evtdata.Key)
case 'uparrow'
move_dir(n) = 3;
case 'downarrow'
move_dir(n) = 4;
case 'w'
move_dir(n) = 3;
case 's'
move_dir(n) = 4;
end
end
end
%Press R to try again. restarting the screen
if(strcmp(evtdata.Key,'r'))
restart();
end
else
%When the game is not running
%Direction keys change the map
if(strcmp(evtdata.Key,'leftarrow') ||strcmp(evtdata.Key,'rightarrow')||...
strcmp(evtdata.Key,'a') ||strcmp(evtdata.Key,'d'))
switch(evtdata.Key)
case 'leftarrow'
map_number = map_number -1;
case 'rightarrow'
map_number = map_number +1;
case 'a'
map_number = map_number -1;
case 'd'
map_number = map_number +1;
end
if map_number>n_of_maps
map_number = 0;
elseif map_number<0
map_number = n_of_maps;
end
restart();
end
end
%Space to start the game
if(strcmp(evtdata.Key,'space'))
if(game_on == 0)
set(load_map_button,'Enable','off');
drawnow;
start(update_t);
game_on =1;
set(console_text,'String',{sprintf('Score : %d\n',floor(score/10));} );
end
end
end
%% Non Callback functions
%Function to update the player coordinates and check is it dead
function[isdead] = move(scr_mat)
isdead = 0;
player_newx = player_body(1,1);player_newy = player_body(2,1);
%Check the next key press if there is one, otherwise last key press
if(length(move_dir)>1)
move_dir = move_dir(2:end);
end
switch(move_dir(1))
case 1
player_newx = player_newx - 1;
case 2
player_newx = player_newx + 1;
case 3
player_newy = player_newy - 1;
case 4
player_newy = player_newy + 1;
end
%Wrap the player around the edge of the map
if player_newx>width
player_newx = 1;
end
if player_newx<1
player_newx = width;
end
if player_newy>height
player_newy = 1;
end
if player_newy<1
player_newy = height;
end
%Check if the head of the player intersect with the body
xcheck = (player_body(1,2:end)==player_newx);
ycheck = (player_body(2,2:end)==player_newy);
if(sum(scr_mat(player_newy,player_newx,:))>2.9 ||any(xcheck & ycheck))
% if(graze <1)
% graze = graze+1;
% else
isdead = 1;
return
%end
else
%graze = 0;
if (player_len >1)
player_body = [[player_newx;player_newy] player_body(:,1:end-1)];
else
player_body = [player_newx;player_newy];
end
end
%Check if the player head intersect with the fruit
if(player_body(1,1) == fruit_x && player_body(2,1) == fruit_y)
fruit_x = -1;
play(beep);
player_len = player_len+1;
player_body = [player_body player_body(:,end)];
score = score + fruit_value;
set(console_text,'String',{sprintf('Score : %d',floor(score/10)),...
sprintf('+%.1f',fruit_value/10)} );
else
%Decrease the fruit value if it is not collected
if fruit_value>10
fruit_value = fruit_value -1;
else
fruit_value = 10;
end
end
end
%Function to spawn the fruit
function [scr_mat] = spawn_fruit(scr_mat)
comp_mat = sum(scr_mat,3);
[empty_y,empty_x] = find(comp_mat==0);
fruit_pos = floor(rand(1)*length(empty_x))+1;
fruit_x = empty_x(fruit_pos);fruit_y = empty_y(fruit_pos);
end
%Function to restart the game
function restart()
stop(update_t); %Stop continuously updating the game
game_on = 0; %Indicate the game is not running
map_load(map_number); %Load the selected map
fruit_x = -1; %Remove the fruit
fruit_value = 1; %Reset the fruit value
score = 0; %Reset the score
update_screen(); %Update the screen
set(console_text,'String',{'WASD or Arrows key to select map','Space to start'});
set(load_map_button,'Enable','on');
end
%Function to load the selected map
function map_load(num)
if(num>0)
map = maze_map{num};
map_sz = size(maze_map{num});
map_sz_norm = map_sz/max(map_sz);
width = map_sz(2);
height = map_sz(1);
set(update_t,'Period',round(1000/speed(num))/1000);
max_value = ceil(60*map_sz(2)*map_sz(1)/900*speed(num)/12.5);
set(console_text,'FontSize',round(default_ftsize*map_sz_norm(2)*map_sz_norm(1)));
player_body = start_body{num};
selected_colour = body_colour{num};
player_len = length(player_body(1,:));
if (player_len>1)
if(player_body(1,1)==player_body(1,2))
if(player_body(2,1)>player_body(2,2))
move_dir = 4;
else
move_dir = 3;
end
else
if(player_body(1,1)>player_body(1,2))
move_dir = 2;
else
move_dir = 1;
end
end
else
move_dir = 2;
end
else
width = 30;
height = 30;
map = zeros(height,width,3);
set(update_t,'Period',default_updatetime);
max_value = 60;
set(console_text,'FontSize',default_ftsize);
player_body = zeros(2,3); %Reset the player body
selected_colour = [0.7 0.2 0.5];
player_headx = round(30/2);
player_heady = round(30/2);
player_len = 3;
for n=1:player_len
player_body(1,n) = player_headx-n+1;
player_body(2,n) = player_heady;
end
move_dir = 2;
end
end
function load_map_pack(fname)
try
mzmp = load(fname);
maze_map = mzmp.map;
n_of_maps = length(maze_map);
map_name = mzmp.map_name;
speed = mzmp.speed;
start_body = mzmp.player_body;
body_colour = mzmp.colours;
map_number = 0;
map_load(map_number);
catch
errorbox = errordlg('mazemap.mat might not exist or not compatible within the directory. No levels loaded','modal');
uiwait(errorbox);
maze_map = {};
n_of_maps = 0;
map_number = 0;
% player_body = zeros(2,3); %Reset the player body
% player_headx = round(30/2);
% player_heady = round(30/2);
% player_len = 3;
% for n=1:player_len
% player_body(1,n) = player_headx-n+1;
% player_body(2,n) = player_heady;
% end
mapload(0);
end
end
%Function to delete the timer when the game is closed
function delete_t(~,~)
stop(update_t);
delete(update_t);
end
function select_mappack(~,~)
winpos = get(win,'Position');
change_pack = 0;change_confirm = 0;
changepack = dialog('Name','Select a Map Pack','Position',[winpos(1:2)+winpos(3:4)/4 winpos(3:4)/1.5]);
matfiles = what;
matfiles = matfiles.mat;
file_listbox = uicontrol('Style','listbox','Units','normalized',...
'Position',[0.1 0.1 0.5 0.85],...
'String',matfiles);
uicontrol('Style','pushbutton','Units','normalized',...
'Position',[0.7 0.7 0.2 0.2],...
'String','Okay','Callback',@confirm_change);
uicontrol('Style','pushbutton','Units','normalized',...
'Position',[0.7 0.5 0.2 0.2],...
'String','Cancel','Callback',@cancel_change);
function confirm_change(~,~)
fnum = get(file_listbox,'value');
change_pack = matfiles{fnum};
change_pack = strrep(change_pack,'.mat','');
change_confirm = 1;
close(changepack);
end
function cancel_change(~,~)
close(changepack);
end
uiwait(changepack);
if(change_confirm)
load_map_pack(change_pack);
restart();
confirm = msgbox('Load Complete','modal');
uiwait(confirm);
end
set(load_map_button,'Enable','off')
drawnow;
set(load_map_button,'Enable','on')
end
end