admin 管理员组文章数量: 887021
2024年3月1日发(作者:linux镜像)
用matlab编写的俄罗斯方块小游戏
•
function RussiaBlock( varargin )
if nargin == 0
OldHandle = findobj( 'Type', 'figure', 'Tag', 'RussiaBlock' ) ;
if ishandle( OldHandle )
delete( OldHandle ) ;
end
FigureHandle = figure( 'Name', '俄罗斯方块MATLAB版', 'Tag', 'RussiaBlock',
'NumberTitle', 'off',...
'Menubar', 'none', 'DoubleBuffer', 'on', 'Resize', 'off', 'visible', 'on',...
'KeyPressFcn', 'RussiaBlock( ''KeyPress_Callback'', gcbo )',...
'HelpFcn', 'helpdlg(''帮不了你- -!'',''不好意思'')',...
'CloseRequestFcn', 'RussiaBlock( ''CloseFigure_Callback'', gcbo )' ) ;
generate_FigureContent( FigureHandle ) ;
init_FigureContent( FigureHandle ) ;
set( FigureHandle, 'Visible', 'on' ) ;
elseif ischar( varargin{1} )
feval( varargin{:} ) ;
end
% -------------------------------------------------------------------------
function generate_FigureContent( FigureHandle )
TabSpace = 30 ;
BlockWidth = 20 ;
BlockHeight = 20 ;
FigureWidth = BlockWidth * (12 + 1) + TabSpace * 7;
FigureHeight = 500 ;
set( FigureHandle, 'Position', [0 0 FigureWidth FigureHeight] ) ;
movegui( FigureHandle, 'center' ) ;
% 创建菜单
BeginMenu = uimenu( FigureHandle, 'Label', '开始' ) ;
StartMenu = uimenu( BeginMenu, 'Label', '开始新游戏', 'Accelerator', 'N',...
'Callback', 'RussiaBlock( ''StartNewGame_Callback'', gcbo )');
SaveMenu = uimenu( BeginMenu, 'Label', '保存', 'Accelerator', 'S', 'Enable', 'off',...
'Separator', 'on', 'Cal', 'RussiaBlock( ''SaveGame_Callback'', gcbo )' );
LoadMenu = uimenu( BeginMenu, 'Label', '读取', 'Accelerator', 'L', 'Enable', 'off',...
'Cal', 'RussiaBlock( ''LoadGame_Callback'', gcbo )' );
QuitMenu = uimenu( BeginMenu, 'Label', '退出', 'Accelerator', 'Q', 'Separator', 'on', 'Cal',
'close(gcf)');
OperationMenu = uimenu( FigureHandle, 'Label', '功能' );
BoardConfigMenu = uimenu( OperationMenu, 'label', '键盘设置', 'Enable', 'off',...
'Cal', 'RussiaBlock( ''BoardConfig_Callback'', gcbo )' );
FigureConfigMenu = uimenu( OperationMenu, 'label', '界面设置', 'Enable', 'off',...
'Cal', 'RussiaBlock( ''FigureConfig_Callback'', gcbo )' );
HighScoreMenu = uimenu( OperationMenu, 'label', '最高记录', 'Separator', 'on',...
'Cal', 'RussiaBlock( ''HighScore_Callback'', gcbo )', 'Enable', 'off' );
GameLevelMenu = uimenu( OperationMenu, 'Label', '游戏难度',...
'Cal','RussiaBlock( ''GameLevel_Callback'', gcbo )' );
HelpMenu = uimenu( FigureHandle, 'Label', '帮助' );
AboutMenu = uimenu( HelpMenu, 'Label', '关于此软件', 'Cal', 'helpdlg(''俄罗斯方块MATLAB版'',''关于此软件…………'')');
HelpDlgMenu = uimenu( HelpMenu, 'Label', '游戏帮助', 'Separator', 'on', 'Cal', 'helpdlg(''帮不了你- -!'',''不好意思'')' );
% 创建工具条,图标可以用imread从图片读取,但图片不要太大
BeginTool = uipushtool( 'ToolTipString', '开始', 'CData', rand(16,16,3), 'Tag', 'BeginTool',...
'ClickedCallback', 'RussiaBlock( ''StartNewGame_Callback'', gcbo )' ) ;
PauseTool = uitoggletool( 'ToolTipString', '暂停', 'Tag', 'PauseTool', 'Tag', 'PauseTool',...
'CData', reshape( repmat( [1 1 0], 16, 16), [16,16,3] ),...
'ClickedCallback', 'RussiaBlock( ''PauseGame_Callback'', gcbo )' ) ;
% 创建游戏窗口
MainWindowXPos = TabSpace;
MainWindowYPos = TabSpace;
MainWindowWidth = BlockWidth * 12 ;
MainWindowHeight = BlockHeight * 22 ;
MainWindowPosition = [MainWindowXPos MainWindowYPos MainWindowWidth
MainWindowHeight] ;
% 定义游戏窗口的右键菜单
AxesContextMenu = uicontextmenu( 'Tag', 'uicontextmenu' ) ;
uimenu( AxesContextMenu, 'Label', '设置窗口颜色', 'Cal',
'RussiaBlock( ''WindowColor_Callback'', gcbo )' )
uimenu( AxesContextMenu, 'Label', '设置背景图片', 'Cal',
'RussiaBlock( ''WindowPicture_Callback'', gcbo )' )
uimenu( AxesContextMenu, 'Label', '设置方块颜色', 'Cal',
'RussiaBlock( ''BlockColor_Callback'', gcbo )' )
uimenu( AxesContextMenu, 'Label', '恢复默认', 'Cal', 'RussiaBlock( ''Default_Callback'',
gcbo )' )
MainAxes = axes( 'Units', 'pixels', 'Pos', MainWindowPosition, 'XTick', [], 'YTick',[],
'XTickLabel', [],...
'YTickLabel', [], 'Box', 'on', 'Tag', 'MainAxes', 'UicontextMenu', AxesContextMenu,...
'XLim', [0 MainWindowWidth], 'YLim', [0 MainWindowHeight] ) ;
hold on;
% 创建一个窗口用于显示下一个方块的图形
NextBlockWndXPos = MainWindowXPos + MainWindowWidth + TabSpace ;
NextBlockWndHeight = 4 * TabSpace + BlockHeight ;
NextBlockWndYPos = MainWindowYPos + MainWindowHeight - NextBlockWndHeight ;
NextBlockWndWidth = TabSpace * 4 + BlockWidth ;
NextBlockWndPosition = [NextBlockWndXPos NextBlockWndYPos NextBlockWndWidth
NextBlockWndHeight] ;
NextBlockAxes = axes( 'Units', 'pixels', 'Pos', NextBlockWndPosition, 'XTick', [], 'YTick',[],...
'XTickLabel', [], 'YTickLabel', [], 'XLim', [0 NextBlockWndWidth],...
'YLim', [0 NextBlockWndHeight], ...
'Box', 'on', 'Tag', 'NextBlockAxes', 'Color', [0.85 0.85 0.85] ) ;
% 创建一组控件,包括(两个文本框用于显示当前方块数和成绩,两个按钮用于暂停和退出)
ButtonTag = { 'QuitButton', 'PauseButton', 'BlockNumText', 'ScoreText' } ;
ButtonStyle = { 'pushbutton', 'togglebutton', 'text', 'text' } ;
FontColor = { [0 0 0], [1 0 0], [0 0 1], [1 0 1] } ;
ButtonColor = { [0.7 0.8 0.9], [0.3 1 0.3], [0.5 1 1], [0.5 1 1] } ;
ButtonString = { '退出', '暂停', '方块数', '积分' };
ButtonCallback = { 'close(gcf)', 'RussiaBlock( ''ButtonPauseGame_Callback'', gcbo )', '', '' } ;
ButtonNumber = length( ButtonTag ) ;
ButtonWidth = NextBlockWndWidth ;
ButtonHeight = 50 ;
ButtonXPos = NextBlockWndXPos ;
ButtonYPos = MainWindowYPos + TabSpace ;
ButtonPosition = [ButtonXPos ButtonYPos ButtonWidth ButtonHeight] ;
ButtonTabSpace = (NextBlockWndYPos - 2 * TabSpace - ButtonHeight * ButtonNumber) /
ButtonNumber ;
for num = 1: ButtonNumber
TempButtonPosition = ButtonPosition ;
TempButtonPosition(2) = ButtonPosition(2) + (num - 1) * (ButtonTabSpace +
ButtonHeight);
if findstr( ButtonStyle{num}, 'button' )
TempButtonPosition(1) = TempButtonPosition(1) + 10 ;
TempButtonPosition(2) = TempButtonPosition(2) + 5 ;
TempButtonPosition(3) = TempButtonPosition(3) - 10 * 2 ;
TempButtonPosition(4) = TempButtonPosition(4) - 5 * 2 ;
else
TempButtonPosition(1) = TempButtonPosition(1) - 10 ;
TempButtonPosition(2) = TempButtonPosition(2) - 5 ;
TempButtonPosition(3) = TempButtonPosition(3) + 10 * 2;
TempButtonPosition(4) = TempButtonPosition(4) + 5 * 2 ;
end
ButtonHandle = uicontrol( 'Tag', ButtonTag{num}, 'Style', ButtonStyle{num}, 'Pos',
TempButtonPosition,...
'Foregroundcolor', FontColor{num}, 'Backgroundcolor', ButtonColor{num},...
'Fontsize', 16, 'String', ButtonString{num}, 'Cal', ButtonCallback{num} ) ;
if findstr( ButtonStyle{num}, 'text' )
set( ButtonHandle, 'Max', 2 ) ;
end
if findstr( ButtonTag{num}, 'PauseButton' )
set( ButtonHandle, 'Enable', 'inactive', 'ButtonDownFcn', ButtonCallback{num}, 'Cal', '' ) ;
end
end
MainBlockAxes = axes( 'Units', 'pixels', 'Pos', MainWindowPosition, 'XTick', [], 'YTick',[],
'XTickLabel', [],...
'YTickLabel', [], 'Box', 'on', 'Tag', 'MainBlockAxes', 'Hittest', 'off',...
'XLim', [0 MainWindowWidth], 'YLim', [0 MainWindowHeight], 'Color', 'none' ) ;
line( 'Visible', 'on', 'Tag', 'BlockHandle', 'Markersize', 18, 'Parent', MainBlockAxes, 'HitTest',
'off',...
'Marker', 's', 'MarkerEdgeColor', 'k', 'XData', nan, 'YData', nan, 'LineStyle', 'none' ) ;
line( 'Visible', 'off', 'Tag', 'TempBlock', 'Markersize', 18, 'Parent', MainBlockAxes, 'HitTest',
'off',...
'Marker', 's', 'MarkerEdgeColor', 'k', 'XData', 130, 'YData', 30, 'LineStyle', 'none' ) ;
line( 'Visible', 'off', 'Tag', 'NextBlock', 'Markersize', 18, 'Parent', NextBlockAxes, 'HitTest',
'off',...
'Marker', 's', 'MarkerEdgeColor', 'k', 'XData', 30, 'YData', 30, 'LineStyle', 'none' ) ;
setappdata( FigureHandle, 'XLim', [0 MainWindowWidth] )
setappdata( FigureHandle, 'YLim', [0 MainWindowHeight] )
handles = guihandles( FigureHandle ) ;
guidata( FigureHandle, handles ) ;
% -------------------------------------------------------------------------
function init_FigureContent( FigureHandle )
handles = guidata( FigureHandle ) ;
ColorInfo = [] ;
try
ColorInfo = load('') ;
catch
end
if isempty( ColorInfo )
olor = GetDefaultBlockColor ;
esColor = GetDefaultMainAxesColor ;
ata = [] ;
end
set( es, 'Color', esColor ) ;
if ~isempty( ata )
ImageHandle = image( ata, 'Parent',
es ) ;
set( ImageHandle, ty ) ;
setappdata( FigureHandle, 'ImageData', ata ) ;
end
set( andle, 'MarkerFaceColor', olor ) ;
set( ock, 'MarkerFaceColor', olor ) ;
set( ock, 'MarkerFaceColor', olor ) ;
setappdata( FigureHandle, 'BlockColor', olor ) ;
% ------------------------------------------------------------
function StartNewGame_Callback( h, StartType )
handles = guidata( h ) ;
global PauseTime
if nargin == 1
StartType = 'NewStart' ;
setappdata( Block, 'BlockNumber', 0 ) ;
set( umText, 'String', {'方块数','0'} ) ;
setappdata( Block, 'CurrentScore', 0 ) ;
set( ext, 'String', {'积分','0'} ) ;
set( andle, 'XData', nan, 'YData', nan ) ;
set( ock, 'XData', nan, 'YData', nan ) ;
TextHandle = findobj( 'Parent', ockAxes, 'Type', 'text' ) ;
delete( TextHandle ) ;
else
end
set( ock, 'Visible', 'on' ) ;
set( ock, 'Visible', 'on' ) ;
set( ool, 'State', 'off' ) ;
set( utton, 'Value', 0 ) ;
YLim = get( es, 'YLim' ) ;
while( ishandle( h ) )
TotalYData = get( andle, 'YData' ) ;
if any( TotalYData >= YLim(2) )
% Game over
text( 20, 200, 'GameOver', 'Parent', ockAxes,...
'FontSize', 30, 'Color', 'r', 'FontAngle', 'italic' ) ;
break;
end
if length( TotalYData ) >= 4
TotalXData = get( andle, 'XData' ) ;
LastBlockYData = TotalYData( end - 3: end ) ;
LastBlockYData = unique( LastBlockYData ) ;
CompleteLine = [] ;
UsefulIndex = [] ;
for num = 1: length( LastBlockYData )
[YData, Index] = find( TotalYData == LastBlockYData(num) ) ;
if length( YData ) == 12
CompleteLine = [CompleteLine, LastBlockYData(num)] ;
UsefulIndex = [UsefulIndex, Index] ;
end
end
if ~isempty( CompleteLine )
TotalXData( UsefulIndex ) = [] ;
TotalYData( UsefulIndex ) = [] ;
LineNumber = length( CompleteLine ) ;
ScoreArray = [100 300 600 1000] ;
NewScore = ScoreArray(LineNumber) ;
CurrentScore = getappdata( Block, 'CurrentScore' ) ;
TextString = get( ext, 'String' ) ;
TextString{2} = CurrentScore + NewScore ;
set( ext, 'String', TextString ) ;
setappdata( Block, 'CurrentScore', CurrentScore + NewScore ) ;
UpdateGameLevel( Block, CurrentScore + NewScore ) ;
% 处理需要下移的方块
for num = LineNumber : -1 : 1
[YData, Index] = find( TotalYData > LastBlockYData(num) ) ;
TotalYData(Index) = TotalYData(Index) - 20 ;
end
end
set( andle, 'XData', TotalXData, 'YData', TotalYData ) ;
end
BlockNumber = getappdata( Block, 'BlockNumber' ) ;
TextString = get( umText, 'String' ) ;
TextString{2} = BlockNumber + 1 ;
set( umText, 'String', TextString ) ;
setappdata( Block, 'BlockNumber', BlockNumber + 1 ) ;
GameLevel = getappdata( Block, 'GameLevel' ) ;
if isempty( GameLevel )
PauseTime = 0.3 ;
else
PauseTime = ceil( 20 / GameLevel ) / 100 ;
end
ep = 0 ;
ep = 0 ;
setappdata( Block, 'TempBlockPos', TempBlockPos ) ;
Status = 1;
[BlockXArray,BlockYArray] = Com_GetBlock( h ) ;
set( ock, 'XData', BlockXArray, 'YData', BlockYArray ) ;
while( Status & ishandle( h ) )
if(PauseTime) ~= 0
pause( PauseTime )
end
Status = test_MoveBlock( h, 'Down' ) ;
end
end
% -------------------------------------------------------------------------
function KeyPress_Callback( h )
handles = guidata( h ) ;
PauseState = get( ool, 'State' ) ;
if strcmp( PauseState, 'on' )
return
end
BoardConfig = getappdata( Block, 'BoardConfig' ) ;
if isempty( BoardConfig )
Left = 'leftarrow' ;
Right = 'rightarrow' ;
Down = 'downarrow' ;
Change = 'uparrow' ;
Drop = 'space' ;
else
Left = ;
Right = ;
Down = ;
Change = ;
Drop = ;
end
CurrentKey = get( Block, 'CurrentKey' ) ;
switch CurrentKey
case Left
test_MoveBlock( h, 'Left' ) ;
case Right
test_MoveBlock( h, 'Right' ) ;
case Down
test_MoveBlock( h, 'Down' ) ;
case Change
test_MoveBlock( h, 'Change' ) ;
case Drop
test_MoveBlock( h, 'Drop' ) ;
otherwise
return ;
end
% -------------------------------------------------------------------------
function WindowColor_Callback( h )
handles = guidata( h ) ;
CurrentColor = get( es, 'Color' ) ;
NewColor = uisetcolor( CurrentColor, '请选择窗口颜色' ) ;
if length( NewColor ) == 0
return;
else
set( es, 'Color', NewColor ) ;
end
% -------------------------------------------------------------------------
function WindowPicture_Callback( h )
handles = guidata( h ) ;
[PictureFile, Path] = uigetfile( {'*.jpg; *.bmp'},'请选择图片' );
if isnumeric( PictureFile )
return ;
else
% if length( PictureFile ) > 31
% errordlg( '文件名过长,读取失败' ) ;
% end
try
Picture = imread( [Path, PictureFile] ) ;
for num = 1: size( Picture, 3 )
ValidPicture(:, :, num) = flipud( Picture(:,:,num) ) ;
end
AxesXLim = get( es, 'XLim' ) ;
AxesYLim = get( es, 'YLim' ) ;
BlockHandle = findobj( es, 'Style', 'line' ) ;
cla( BlockHandle ) ;
ImageXLimit = size(Picture, 2) ;
ImageYLimit = size(Picture, 1) ;
if diff( AxesXLim ) < size(Picture, 2) | diff( AxesYLim ) < size(Picture, 1)
% 超出坐标轴范围,压缩显示
XScale = diff( AxesXLim ) / size(Picture, 2) ;
YScale = diff( AxesYLim ) / size(Picture, 1) ;
% 取较小比例压缩
Scale = min( XScale, YScale ) ;
ImageXLimit = size(Picture, 2) * Scale ;
ImageYLimit = size(Picture, 1) * Scale ;
end
ImageXData(1) = AxesXLim(1) + (diff( AxesXLim ) - ImageXLimit) / 2 + 1;
ImageXData(2) = ImageXData(1) + ImageXLimit - 1;
ImageYData(1) = AxesYLim(1) + (diff( AxesYLim ) - ImageYLimit) / 2 + 1;
ImageYData(2) = ImageYData(1) + ImageYLimit - 1;
image( ValidPicture, 'Parent', es, 'Hittest', 'off', ...
'XData',ImageXData,'YData',ImageYData, 'Tag', 'MainImage' );
setappdata( Block, 'ImageData', ValidPicture ) ;
catch
ErrorString = sprintf( ['读取图片失败,错误信息为:n',lasterr] ) ;
errordlg( ErrorString ) ;
end
end
% -------------------------------------------------------------------------
function BlockColor_Callback( h )
handles = guidata( h ) ;
CurrentColor = getappdata( Block, 'BlockColor' ) ;
if isempty( CurrentColor )
CurrentColor = GetDefaultBlockColor ;
setappdata( Block, 'BlockColor', CurrentColor ) ;
end
NewColor = uisetcolor( CurrentColor, '请选择方块颜色' ) ;
if length( NewColor ) == 0
return;
else
setappdata( Block, 'BlockColor', NewColor ) ;
set( andle, 'MarkerFaceColor', NewColor ) ;
set( ock, 'MarkerFaceColor', NewColor ) ;
set( ock, 'MarkerFaceColor', NewColor ) ;
end
% ------------------------------------------------------------------------
function Default_Callback( h )
handles = guidata( h ) ;
BlockColor = GetDefaultBlockColor ;
AxesColor = GetDefaultMainAxesColor ;
set( es, 'Color', AxesColor ) ;
set( andle, 'MarkerFaceColor', BlockColor ) ;
set( ock, 'MarkerFaceColor', BlockColor ) ;
set( ock, 'MarkerFaceColor', BlockColor ) ;
% -------------------------------------------------------------------------
function PauseGame_Callback( h )
handles = guidata( h ) ;
ToolStart = get( ool, 'State' ) ;
if strcmp( ToolStart, 'on' )
set( utton, 'Value', 1 ) ;
waitfor( ool, 'State', 'off' ) ;
else
set( utton, 'Value', 0 ) ;
end
% -------------------------------------------------------------------------
function ButtonPauseGame_Callback( h )
handles = guidata( h ) ;
ToggleButtonValue = get( h, 'Value' ) ;
if ToggleButtonValue == 0
set( h, 'Value', 1 ) ;
set( h, 'String', '继续' ) ;
set( ool, 'State', 'on' ) ;
waitfor( ool, 'State', 'off' ) ;
else
set( h, 'Value', 0 ) ;
set( h, 'String', '暂停' ) ;
set( ool, 'State', 'off' ) ;
set( Block, 'CurrentObject', es ) ;
end
% ------------------------------------------------------------------------
function CloseFigure_Callback( h )
handles = guidata( h ) ;
BlockColor = getappdata( Block, 'BlockColor' ) ;
MainAxesColor = get( es, 'Color' ) ;
MainAxesImageHandle = findobj( es, 'Type', 'image' ) ;
if ~isempty( MainAxesImageHandle )
= get( MainAxesImageHandle, 'Tag' );
t = get( MainAxesImageHandle, 'Hittest' );
= get( MainAxesImageHandle, 'XData' );
= get( MainAxesImageHandle, 'YData' );
ata = getappdata( Block, 'ImageData' ) ;
else
ata = [] ;
end
save BlockColor MainAxesColor MainAxesImage
delete( Block ) ;
% -------------------------------------------------------------------------
function Color = GetDefaultBlockColor
Color = [0 0 1] ;
% -------------------------------------------------------------------------
function Color = GetDefaultMainAxesColor
Color = [1 1 1] ;
% ----------------------------------------------------------------
function [BlockXArray, BlockYArray] = Com_GetBlock( varargin )
global BlockIndex ;
BlockXArray = [] ;
BlockYArray = [] ;
handles = guidata( varargin{1} ) ;
if nargin == 1
BlockArray = getappdata( Block, 'BlockArray' ) ;
BlockIndex = ceil( rand(1) * 24 ) ;
else % nargin == 2
BlockIndex = varargin{2} ;
end
switch(BlockIndex)
case {1,2,3,4} % 方块
BlockXArray = [0;0;1;1] * 20 - 10 ;
BlockYArray = [0;1;1;0] * 20 - 10 ;
case {5,6} % 竖长条
BlockXArray = [0;0;0;0] * 20 - 10 ;
BlockYArray = [-1;0;1;2] * 20 - 10 ;
case {7,8} % 横长条
BlockXArray = [-1;0;1;2] * 20 - 10 ;
BlockYArray = [1;1;1;1] * 20 - 10 ;
case {9} % 4类T T1
BlockXArray = [-1;0;1;0] * 20 - 10 ;
BlockYArray = [1;1;1;0] * 20 - 10 ;
case {10} % T2
BlockXArray = [0;0;1;0] * 20 - 10 ;
BlockYArray = [2;1;1;0] * 20 - 10 ;
case {11} % T3
BlockXArray = [0;0;1;-1] * 20 - 10 ;
BlockYArray = [2;1;1;1] * 20 - 10 ;
case {12} % T4
BlockXArray = [0;0;0;-1] * 20 - 10 ;
BlockYArray = [2;1;0;1] * 20 - 10 ;
case {13} % 8类L L1
BlockXArray = [0;0;0;1] * 20 - 10 ;
BlockYArray = [1;0;-1;-1] * 20 - 10 ;
case {14} % L2
BlockXArray = [-1;0;1;1] * 20 - 10 ;
BlockYArray = [0;0;0;1] * 20 - 10 ;
case {15} % L3
BlockXArray = [-1;0;0;0] * 20 - 10 ;
BlockYArray = [1;1;0;-1] * 20 - 10 ;
case {16} % L4
BlockXArray = [-1;-1;0;1] * 20 - 10 ;
BlockYArray = [-1;0;0;0] * 20 - 10 ;
case {17} % L5
BlockXArray = [-1;0;0;0] * 20 - 10 ;
BlockYArray = [-1;-1;0;1] * 20 - 10 ;
case {18} % L6
BlockXArray = [-1;-1;0;1] * 20 - 10 ;
BlockYArray = [1;0;0;0] * 20 - 10 ;
case {19} % L7
BlockXArray = [0;0;0;1] * 20 - 10 ;
BlockYArray = [-1;0;1;1] * 20 - 10 ;
case {20} % L8
BlockXArray = [-1;0;1;1] * 20 - 10 ;
BlockYArray = [0;0;0;-1] * 20 - 10 ;
case {21 22} % 4类Z Z1
BlockXArray = [-1;0;0;1] * 20 - 10 ;
BlockYArray = [1;1;0;0] * 20 - 10 ;
case {23 24} % Z2
BlockXArray = [0;0;1;1] * 20 - 10 ;
BlockYArray = [-1;0;0;1] * 20 - 10 ;
case {25 26} % Z3
BlockXArray = [-1;0;0;1] * 20 - 10 ;
BlockYArray = [0;0;1;1] * 20 - 10 ;
case {27 28} % Z4
BlockXArray = [0;0;1;1] * 20 - 10 ;
BlockYArray = [1;0;0;-1] * 20 - 10 ;
end
if nargin == 1
Array = BlockXArray ;
Array = BlockYArray ;
ndex = BlockIndex ;
NextAxesXLim = get( ockAxes, 'XLim' ) ;
NextAxesYLim = get( ockAxes, 'YLim' ) ;
set( ock, 'XData', [BlockXArray + 0.5 * diff( NextAxesXLim ) -
ceil( sum( BlockXArray ) / 4 ) ],...
'YData', [BlockYArray + 0.5 * diff( NextAxesYLim )] - ceil( sum( BlockYArray ) / 4 ) ) ;
setappdata( Block, 'BlockArray', NewBlockArray ) ;
if isempty( BlockArray )
Com_GetBlock( varargin{1} ) ;
else
BlockXArray = Array ;
BlockYArray = Array ;
BlockIndex = ndex ;
end
end
AxesXLim = getappdata( Block, 'XLim' ) ;
AxesYLim = getappdata( Block, 'YLim' ) ;
BlockXArray = BlockXArray + 0.5 * diff( AxesXLim ) ;
BlockYArray = BlockYArray + diff( AxesYLim ) ;
% -------------------------------------------------------------------------
function Status = test_MoveBlock( h, MoveMode )
Status = 1;
if ~ishandle( h )
return
end
handles = guidata( h ) ;
TempXData = get( ock, 'XData' ) ;
TempYData = get( ock, 'YData' ) ;
TempXData = TempXData';
TempYData = TempYData' ;
TotalXData = get( andle, 'XData' ) ;
TotalYData = get( andle, 'YData' ) ;
TotalXData = TotalXData' ;
TotalYData = TotalYData' ;
TempBlockPos = getappdata( Block, 'TempBlockPos' ) ;
if isempty( TempBlockPos )
return
end
AxesXLim = getappdata( Block, 'XLim' ) ;
AxesYLim = getappdata( Block, 'YLim' ) ;
switch MoveMode
case 'Left'
if any( TempXData - 20 < AxesXLim(1) )
return
end
TestArray = ismember( [TempXData - 20, TempYData], [TotalXData, TotalYData],
'rows' ) ;
if any( TestArray )
return;
else
set( ock, 'XData', TempXData - 20 ) ;
ep = ep + 1 ;
setappdata( Block, 'TempBlockPos', TempBlockPos ) ;
end
case 'Right'
if any( TempXData + 20 > AxesXLim(2) )
return
end
TestArray = ismember( [TempXData + 20, TempYData], [TotalXData, TotalYData],
'rows' ) ;
if any( TestArray )
return;
else
set( ock, 'XData', TempXData + 20 ) ;
ep = ep - 1 ;
setappdata( Block, 'TempBlockPos', TempBlockPos ) ;
end
case 'Down'
if any( TempYData - 20 < AxesYLim(1) )
set( andle, 'XData', [TotalXData; TempXData],...
'YData', [TotalYData; TempYData] ) ;
Status = 0 ;
return
end
TestArray = ismember( [TempXData, TempYData - 20], [TotalXData, TotalYData],
'rows' ) ;
if any( TestArray )
set( andle, 'XData', [TotalXData; TempXData],...
'YData', [TotalYData; TempYData] ) ;
Status = 0 ;
else
set( ock, 'YData', TempYData - 20 ) ;
ep = ep + 1 ;
setappdata( Block, 'TempBlockPos', TempBlockPos ) ;
end
case 'Drop'
global PauseTime
PauseTime = 0 ;
case 'Change'
global BlockIndex
OldBlockIndex = BlockIndex ;
switch BlockIndex
case {1,2,3,4}
return;
case {5,6}
NewIndex = 7 ;
case {7,8}
NewIndex = 5 ;
case {9,10,11,12}
NewIndex = mod( OldBlockIndex, 4 ) + 9;
case {13,14,15,16}
NewIndex = mod( OldBlockIndex, 4 ) + 13;
case {17,18,19,20}
NewIndex = mod( OldBlockIndex, 4 ) + 17;
case {21,22}
NewIndex = 23;
case {23,24}
NewIndex = 21;
case {25,26}
NewIndex = 27 ;
case {27,28}
NewIndex = 25 ;
end
[BlockXArray, BlockYArray] = Com_GetBlock( h, NewIndex ) ;
NewTempXData = BlockXArray - ep * 20 ;
NewTempYData = BlockYArray - ep * 20 ;
if any( NewTempXData < AxesXLim(1) ) | any( NewTempXData > AxesXLim(2) ) |...
any( NewTempYData < AxesYLim(1) )
BlockIndex = OldBlockIndex ;
return;
end
TestArray = ismember( [NewTempXData, NewTempYData], [TotalXData, TotalYData],
'rows' ) ;
if any( TestArray )
BlockIndex = OldBlockIndex ;
else
BlockIndex = NewIndex ;
set( ock, 'XData', NewTempXData, 'YData', NewTempYData ) ;
end
end
% -------------------------------------------------------------------------
function UpdateGameLevel( FigureHandle, Score ) ;
GameLevel = ceil( Score / 10000 ) ;
if GameLevel > 9
GameLevel = 9 ;
end
setappdata( FigureHandle, 'GameLevel', GameLevel ) ;
% -------------------------------------------------------------------------
function GameLevel_Callback( h )
handles = guidata( h ) ;
ScoreFigure = figure( 'name', '游戏难度设置', 'menubar', 'none', 'numbertitle', 'off',...
'pos', [200 200 200 180], 'windowstyle', 'modal', 'resize', 'off' ) ;
uicontrol( 'Parent', ScoreFigure, 'Style', 'listbox', 'Pos', [20 20 80 140],...
'String', [sprintf( '%d 级|', 1:8 ),'9 级'] ) ;
uicontrol( 'Parent', ScoreFigure, 'Style', 'pushbutton', 'Pos', [120 100 60 50], 'String', '确定',...
'Cal', ['GameLevel = get( findobj( ''Style'', ''listbox''), ''Value'');',...
'set( 0, ''Userdata'', GameLevel ); close( gcf );'] ) ;
uicontrol( 'Parent', ScoreFigure, 'Style', 'pushbutton', 'Pos', [120 30 60 50], 'String', '取消',...
'Cal', 'close( gcf )' ) ;
waitfor( ScoreFigure ) ;
ButtonAction = questdlg( '重新设置游戏难度将初始化界面,是否继续?', '设置确认', '是的', '取消', '取消' ) ;
if strcmp( '取消', ButtonAction )
return
end
GameLevel = get( 0, 'Userdata' ) ;
setappdata( Block, 'GameLevel', GameLevel ) ;
摘 要
随着科技的发展,许多用户希望在工作之余有一定的娱乐,而贪吃蛇这款经典游戏正符合大众的心里。因此,为了迎合众多用户的需求,我们开发出一套适合各阶层人士的具有很强的娱乐性和交互性的贪吃蛇小游戏。
贪吃蛇,之所以取这样的名字,去用意还是很明显的.贪吃蛇其实并不贪,它是人不断向前追求的象征.就像现代的人只有不断努力向前才能得到自己想要的。而食物也是随机出现的,就像现在社会存在的机会,而我们只有找好自己的目标才能成功。
虽然现在市面上存在着各种各样的游戏版本,可是贪吃蛇其市场还是相当大的。因为它的特殊在于它能吸引人更深入,爱不释手.随着游戏速度不断加快,其刺激性也更强。可以说该游戏的优势在于它的简单易行,还在于它很快顺利的运行。对于在外忙碌的人,不可能花费大量时间在娱乐上,大型游戏是行不通的。这样的小游戏刚好迎合了他们的需求。
关键词: 贪吃蛇,汇编语言,函数,游戏
目 录
目 录 ............................................................................................................................................ 18
前 言 ............................................................................................................................................ 19
第1章 系统分析 .......................................................................................................................... 20
1.1 需求概述 ........................................................................................................................ 20
1.2 需求环境 ........................................................................................................................ 20
1.3 功能描述 ........................................................................................................................ 20
第2章 系统总体设计................................................................................................................... 21
2.1 程序功能模块................................................................................................................. 21
2.2 程序流程图..................................................................................................................... 22
第3章 详细设计 .......................................................................................................................... 23
3.1详细设计 ......................................................................................................................... 23
3.1.1 数据段................................................................................................................. 23
3.1.2代码段.................................................................................................................. 23
3.1.3 初始化新游戏的各种状态 ................................................................................. 25
3.1.4 蛇身移动............................................................................................................. 25
3.1.5 窗口过程............................................................................................................. 26
3.1.6 入口函数............................................................................................................. 30
4.1可行性分析...................................................................................................................... 32
4.2测试结果分析.................................................................................................................. 32
第5章 软件使用说明书 .............................................................................................................. 33
5.1游戏运行截图.................................................................................................................. 33
参考文献 ........................................................................................................................................ 38
致 谢 .......................................................................................................................................... 39
附 录 .......................................................................................................................................... 40
前 言
人类已经跨入了二十二世纪,正在进入信息时代。计算机技术和通讯技术的发展和应用及,促进了社会的高速发展,同时也改变着人们的工作、学习、生活和娱乐的方式以及思想观念。随着计算机的日益普及,工作的生活节奏的加快,休闲小游戏越来越受到人们的青睐,尤其贪食蛇类的经典游戏在人类的生活娱乐中占有一席之地,随着计算机技术的成熟,各种各样的贪食蛇游戏也流传在网路中,人们可以方便的体验别样风格的贪食蛇。
第1章 系统分析
1.1 需求概述
本设计所开发的是基于汇编语言的一个贪吃蛇游戏软件,程序关键在于表示蛇的图形及蛇的移动。用一个小矩形快表示蛇的一节身体,身体每长一节,增加一个矩形块,蛇头用俩节表示。移动时必须从蛇头开始,所以蛇不能向相反的方向移动,如果不按任意键,蛇自行在当前方向上前移,但按下有效方向键后,蛇头朝着该方向移动,一步移动一节身体,所以按下有效方向键后,先确定蛇头的位置,而后蛇的身体随蛇头移动,图形的实现是从蛇头新位置开始画出蛇,这时,由于未清屏的原因,原来的蛇的位置和新蛇的位置差一个单位,所以看起来蛇多一节身体,所以将蛇的最后一节用背景色覆盖。食物的出现与消失也是画矩形块和覆盖矩形块。蛇撞在墙上则游戏结束。
1.2 需求环境
本课程设计需要的设备为硬件要求和软件配置要求具体要求如下:
①硬件要求:一台计算机。
②软件配置:WINDOWS运行环境
1.3 功能描述
本课程设计是利用图形学的相关知识在Windows环境下利用窗口化界面实现经典贪吃蛇游戏,其基本的功能描述如下:
此游戏程序应实现使一条蛇在密闭的围墙内游动,在围墙内随机出现一个食物,通过按键盘上的四个光标键控制蛇向上、下、左、右四个方向移动,蛇头撞到食物时,则表示食物被蛇吃掉,蛇的身体同时增长一节,并同时计分加10分,接着再出现食物,重复刚才的过程。如果蛇在移动过程中,撞到墙壁或身体交叉即蛇头撞到自己的身体,则游戏结束。
第2章 系统总体设计
贪吃蛇是一个家喻户晓的益智类小游戏。本设计是采用汇编中的宏定义和调用,子程序的调用,BIOS,DOS中断等一些汇编知识编制而成的一个贪吃蛇小游戏,通过这个小游戏的制作,我们可以得到很多的益处:巩固微机原理与汇编语言的基础知识:进一步掌握计算机软,硬件设计方法;增强了软件开发过程中实际操作的能力;能够掌握如何使用汇编语言进行键盘控制,显示控制等功能。
2.1 程序功能模块
由需求分析知,本次课程设计是用方向键实现贪吃蛇游戏程序,故其功能模块分为:开始画面(描绘围墙、蛇体、食物等及其颜色),游戏过程(通过四个方向键控制蛇头带动身体移动),游戏结束(显示总分并判断是否重新游戏)模块三个模块。
开始游戏
开始画面
游戏过程
游戏结束
是否重新游戏
关闭程序
图2.1 功能模块图
2.2 程序流程图
开始
定义结构体数组food和snake存食物和蛇(life存活为0,死亡为1),设置围墙格式
游戏开始画面
蛇初始向右移动,方向键改变移动方向
Life==0
继续游戏
游戏结束
蛇长度和分增加,继续控制
蛇移动 重新开始
游戏结束,显示最终得分
关闭程序
2.2 程序流程图
第3章 详细设计
3.1详细设计
主要功能模块的算法设计思路:
3.1.1 数据段
szCaptionMain db '贪食蛇',0
szCaptionPause db '已暂停',0
szCaptionDie db '游戏结束,请按N键开始新游戏',0
szDown db '下',0
szUp db '上',0
szRight db '右',0
szLeft db '左',0
szScore db '得分:%d',0
3.1.2代码段
包括随机数的生成,初始化所有蛇身节点把前三个置为有效,商是y坐标,玉树是X坐标,数组的首元素即为蛇尾,最后一个不为零的元素为蛇头,查看指定结点是否在(x, y) ,在绘制单个节点中先取标志状态,如果是无效,直接退出下一个食物,总是随机出现。更好的方法应该是把所有结点串成两个链表,蛇身链表和非, 蛇身链表。每次随机地从非蛇身链表里取出结点插入蛇身链表中,这样就不会造成随机生成的位置在蛇身上从而重新生成了。
.code
; 随机数生成
_NextInt proc uses edx ebx max
push edx
invoke GetTickCount
add eax, seed
add seed, eax
xor edx, edx
mov ebx, max
div ebx
xor seed, eax
mov eax, edx
inc eax
pop edx
ret
_NextInt endp
; 初始化所有蛇身结点把前三个置为有效
_InitNodes proc
push edi
push edx
push ebx
push ecx
xor edi, edi
@@: xor edx, edx
mov eax, edi
mov ebx, 17h
div ebx; 商是 y 坐标,余数是 x 坐标
xor ecx, ecx
or ecx, edx
inc ecx
shl ecx,8
or ecx, eax
inc ecx
shl ecx,8
or ecx, BODY
shl ecx,8 ; ecx 为结点, ebx 为有效结点列表
; nodeList 数组首元素即蛇尾,最后一个不为0的元素为蛇头
xor ebx, ebx
.if edi <4
or ecx,1
mov ebx, ecx
.endif
mov [offset nodes + edi *4], ecx
mov [offset nodeList + edi *4], ebx
inc edi .if edi >= 187h
jmp @F
.endif
jmp @B
@@: pop ecx
pop ebx
pop edx
pop edi
ret
_InitNodes endp
3.1.3 初始化新游戏的各种状态
_NewGame proc
invoke _InitNodes
invoke _NextFood
mov bTurnPending, FALSE
mov isPaused,0
mov isAlive,1
mov score,0
mov speed,8
mov timerCounts,0
mov eatCounts,0
mov curX,4
mov curY,1
mov direction, RIGHT
ret
_NewGame endp
3.1.4 蛇身移动
_Move proc
Local @nextX: DWORD
Local @nextY: DWORD
push ebx
push curX
push curY
pop @nextY
pop @nextX
mov bTurnPending, FALSE
.if direction == RIGHT
inc @nextX
.elseif direction == DOWN
inc @nextY
.elseif direction == LEFT
dec @nextX
.elseif direction == UP
dec @nextY
.endif
.if (@nextX ==0) || (@nextX >23) || (@nextY ==0) || (@nextY >17)
mov isAlive,0
jmp @F
.endif
invoke _QueryNodeStat, @nextX, @nextY
.if eax
mov isAlive,0
jmp @F
.endif
mov eax, foodX
mov ebx, foodY
.if (@nextX == eax) && (@nextY == ebx)
invoke _PieFromSky
.endif; 头的处理,下一个位置即将激活
invoke _Activate, @nextX, @nextY,1
push @nextX
push @nextY
pop curY
pop curX; 把新头加入队列头,并指示移除队列尾
invoke _GetNodeAt, curX, curY
invoke _AddBody, eax, TRUE
@@: pop ebx
Ret
_Move endp
3.1.5 窗口过程
_ProcWinMain proc hWnd, uMsg, wParam, lParam
Local @stPs:PAINTSTRUCT
Local @stRect:RECT
Local @hBmp: HBITMAP
Local @hOldBmp: HBITMAP
Local @memDC: HDC
Local @hDC: HDC
mov eax, uMsg
.if eax == WM_PAINT
invoke BeginPaint, hWnd, addr @stPs
mov @hDC, eax
invoke CreateCompatibleBitmap, @hDC, wndWidth, wndHeight
mov @hBmp, eax
invoke CreateCompatibleDC, @hDC
mov @memDC, eax
invoke SelectObject, @memDC, @hBmp
mov @hOldBmp, eax
invoke _DrawBody, @memDC
invoke _DrawNode, @memDC, food
invoke _DrawScore, @memDC
invoke BitBlt, @hDC, , , wndWidth, wndHeight,
@memDC, , , SRCCOPY
invoke SelectObject, @memDC, @hOldBmp
invoke DeleteObject, @hBmp
invoke DeleteDC, @memDC
invoke EndPaint, hWnd, addr @stPs
.elseif eax == WM_TIMER
.if !isAlive
invoke SetWindowText, hWnd, offset szCaptionDie
jmp @F
.endif
.if isPaused
jmp @F
.endif
mov eax, timerCounts
.if speed != eax
inc timerCounts
jmp @F
.endif
mov timerCounts,0
invoke _Move
invoke InvalidateRect, hWnd, addr rClient, FALSE
.elseif eax == WM_CLOSE
invoke KillTimer, hWnd, TIMER
invoke DestroyWindow, hWinMain
invoke PostQuitMessage, NULL
.elseif eax == WM_CREATE
invoke SetTimer, hWnd, TIMER,100, NULL
invoke GetClientRect, hWnd, offset rClient
mov bRanColor, TRUE
mov eax,
sub eax,
mov wndWidth, eax
mov eax,
sub eax,
mov wndHeight, eax
invoke _NewGame
.elseif eax == WM_KEYDOWN
mov eax, wParam; 按P键暂停游戏
.if eax =='P'
.if isPaused
and isPaused,0
invoke SetWindowText, hWnd, offset szCaptionMain
.else
or isPaused,1
invoke SetWindowText, hWnd, offset szCaptionPause
.endif; 按了上键
.elseif eax =='W' || eax == VK_UP
.if isPaused || bTurnPending
jmp @F
.endif
mov eax, direction
.if eax == RIGHT || eax == LEFT
push UP
pop direction
invoke SetWindowText, hWnd, offset szUp
mov bTurnPending, TRUE
.endif
; 按了下键
.elseif eax =='S' || eax == VK_DOWN
.if isPaused || bTurnPending
jmp @F
.endif
mov eax, direction
.if eax == RIGHT || eax == LEFT
push DOWN
pop direction
invoke SetWindowText, hWnd, offset szDown
mov bTurnPending, TRUE
.endif; 按了左键
.elseif eax =='A' || eax == VK_LEFT
.if isPaused || bTurnPending
jmp @F
.endif
mov eax, direction
.if eax == UP || eax == DOWN
push LEFT
pop direction
invoke SetWindowText, hWnd, offset szLeft
mov bTurnPending, TRUE
.endif; 按了右键
.elseif eax =='D' || eax == VK_RIGHT
.if isPaused || bTurnPending
jmp @F
.endif
mov eax, direction
.if eax == UP || eax == DOWN
push RIGHT
pop direction
invoke SetWindowText, hWnd, offset szRight
mov bTurnPending, TRUE
.endif
.elseif eax =='C'
.if bRanColor
and bRanColor,0
.else
or bRanColor,1
.endif; Q或者ESC退出游戏
.elseif eax =='Q' || eax == VK_ESCAPE
invoke PostQuitMessage,0 ; 开始新游戏
.elseif eax =='N'
invoke _NewGame
invoke SetWindowText, hWnd, offset szCaptionMain
.endif
.else
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.endif
@@: xor eax, eax
Ret
_ProcWinMain endp
3.1.6 入口函数
_Main proc
Local @stWndClass:WNDCLASSEX
Local @stMsg:MSG
mov food, FALSE
invoke RtlZeroMemory, addr @stWndClass, sizeof @stWndClass
invoke GetModuleHandle, NULL
************************,eax invoke LoadCursor, NULL, IDC_ARROW
**********************,eax invoke LoadIcon, NULL, IDI_INFORMATION
********************,eax*********************,sizeofWNDCLASSEX********************,CS_HREDRAWorCS_VREDRAW**************************,offset_ProcWinMain****************************,COLOR_WINDOW****************************,offsetszClassNameinvoke RegisterClassEx, addr @stWndClass; 显示窗口
invoke CreateWindowEx, WS_EX_CLIENTEDGE, offset szClassName,
offset szCaptionMain,
WS_OVERLAPPEDWINDOW and not WS_MAXIMIZEBOX and not WS_THICKFRAME,
200,100,500,404, NULL, NULL, hInstance, NULL
mov hWinMain, eax
invoke ShowWindow, hWinMain, SW_SHOWNORMAL
invoke UpdateWindow, hWinMain
; 消息循环
.while TRUE
invoke GetMessage, addr @stMsg, NULL,0,0
.break .if eax ==0
invoke TranslateMessage, addr @stMsg
invoke DispatchMessage, addr @stMsg
.endw
ret
_Main endp
start:
call _Main
invoke ExitProcess, NULL
end start
第4章 系统测试
4.1可行性分析
首先,8086指令系统中包括了较为齐全的Dos系统功能调用指令,利用这些指令我们可以实现Dos键盘功能调用和Dos显示功能调用,这就为该游戏的显示和操作提供了条件,使人机对话操作成为了可能;其次,该游戏本身的程序设计并非异常的复杂,无需使用高级语言程序也能够实现,这给汇编语言编写提供了可能,也使得程序量不至于过大而难以实现;此外,经过一个学期8086微机系统的学习我们基本掌握了8086的编程操作,具备了一定的编写程序的能力,并能够自行查找资料独立解决Dos系统功能调用问题(未授);最后也是最重要的一点:我们拥有“贪吃蛇”游戏的示例程序,这让编程能力有限的我能够有章可循不至于无从下手,通过对该示例的了解、分析优化、改进逐步实现设计的预设功能得到较为满意的设计结果。
4.2测试结果分析
贪吃蛇的各个功能都已经实现,可以很好的进行游戏。在游戏过程中发现的bug都已在修改中修复。但是还存在问题,就是如果蛇头的前方是墙壁或者蛇身的话,游戏一定失败。无论反应多快。这个是还待修改但为修改的地方。
第5章 软件使用说明书
双击开始游戏,在游戏中使用键盘方向键控制蛇头方向前进,游戏中蛇头为白色方块,食物为绿色方块,当蛇头触到墙或自身时游戏结束,此时按键盘N,再次开始游戏,游戏中按P,可暂停游戏,再次按P继续游戏。按C可变换蛇身颜色,当需要游戏结束时可关闭窗口、按ESC或按Q键均可关闭。
5.1游戏运行截图
1、游戏开始
2、游戏暂停
3、游戏控制—上
4、游戏控制—下
5、游戏控制—左
6、游戏控制—右
7、游戏中变换蛇身颜色
设计总结
紧张而有趣的课程设计结束了,虽然只有短短的一周时间,可我却获益匪浅,而从中体会到的乐趣更是难以用言语表达。
这次我们组做的题目是小游戏贪吃蛇,我负责的那部分是开始新游戏时的初始化,蛇身移动,窗口过程和入口函数。初看题目,真有点摸不找头脑的感觉,可经过我们小组成员的共同讨论,各抒己见,还有指导老师的讲解分析,我们每一个人都大体清楚了个人的模块和总体的框架,找到了入手点。
通过这次课程设计我对汇编语言有了进一步的了解。知道编制图形程序是程序设计中非常有趣和有价值的工作之一,在图形绘制方面,汇编语言具有潜在的优点,因为显示屏幕上的每一个图象都是由成千上万的元素组成,处理这些象素需要大量的指令,就速度而言,汇编语言比高级语言要快的多。程序采用的是调色板来配置颜色的,虽然颜色的选择很方便,但是美中不足的是它供选择的颜色过于单调。
在此次课程设计中我认识到,写一段代码,首先让它可以运行,然后让它可以正确的运行,最后再去提高效率。写好一段代码比调试一段代码的时间要少的多,而许多许多的问题也是在你写代码的时候所不能发现的。
想想看一路过来学过的课程都是如此:算法数据结构教会我们在什么情况下应该选取怎样的方式去处理数据,操作系统教会我们系统如何处理数据,编译原理教会我们编译器如何处理数据。语言也是一种处理数据的工具,没有哪种工具是万能的,只有合适的场合采用合适的工具。同时,以后再学习一种新的“规则”时,也需要抓住这些重点:这个规则适用的场合,适用的数据,处理数据的方式。
最后,感谢我组每一位同学在此次课程设计中作出的努力,和老师的帮助和指导。
参考文献
[1] 王爽编著.《汇编语言—第二版》.清华大学出版社,2008.4
[2] 沈美明,温冬婵.IBM-PC汇编语言程序设计(第二版).清华大学出版社,
2001。
[3] [美]Kip 著,温玉洁,等译.Intel汇编语言程序设计(第五版).电子工业出版社, 2007。
[4]钱晓捷.汇编语言程序设计(第二版). 电子工业出版社, 2003。
[5] 罗云彬.Windows环境下32位汇编语言程序设计(第二版).电子工业出版社, 2006。
[6] Windows API函数参考手册.人民邮电出版社, 2002。
[7]参考网址:
[8]参考网址:
致 谢
通过这段时间的学习,我学会了很多东西。同时也非常感谢刘老师这段时间的教育与指导。使我从对程序一无所知到勉强能够看懂程序,同时也使我了解到了程序的博大精深,体会到编制程序的无穷乐趣。这段时间的学习我看到了老师无私的奉献,也看到了老师不辞辛苦的来回奔波,让我们非常的感动,同时也更加的激发起了我们学习的兴趣。
附 录
;****************************************************************
.386
.model flat, stdcall
option casemap:none
;****************************************************************
;Include
;****************************************************************
include
include
includelib
include
includelib
include
includelib
includelib
;****************************************************************
; 这个结构并未使用,只是大致描述下一个结点的样子,一个节点是一个DWORD *
; 从高位到低位分别是: x坐标 y坐标 类型(食物或蛇身) 有效标志 *
; 每个字段点一个字节 *
;****************************************************************
Node struct
x BYTE ?
y BYTE ?
ntype BYTE ?
bValid BYTE ?
Node ends
TIMER equ 1
FOOD equ 0
BODY equ 1
RIGHT equ 2
LEFT equ 3
UP equ 4
DOWN equ 5
;****************************************************************
; 数据段
;****************************************************************
.data?
hInstance dd ?
hWinMain dd ?
hDc dd ?
isPaused dd ?
isAlive dd ?
bRanColor dd ?
bTurnPending dd ?
direction dd ?
food dd ?
nodes dd 391 dup (?)
nodeList dd 391 dup (?)
curX dd ?
curY dd ?
foodX dd ?
foodY dd ?
score dd ?
rClient RECT <>
wndWidth dd ?
wndHeight dd ?
szScoreBuffer db 32 dup (?)
seed dd ?
speed dd ?
timerCounts dd ?
eatCounts dd ?
.const
szClassName db '1',0
szCaptionMain db '贪食蛇',0
szCaptionPause db '已暂停',0
szCaptionDie db '游戏结束,请按N键开始新游戏',0
szDown db '下',0
szUp db '上',0
szRight db '右',0
szLeft db '左',0
szScore db '得分:%d',0
;****************************************************************
; 代码段
;****************************************************************
.code
;****************************************************************
; 随机数生成
;****************************************************************
_NextInt proc uses edx ebx max
push edx
invoke GetTickCount
add eax, seed
add seed, eax
xor edx, edx
mov ebx, max
div ebx
xor seed, eax
mov eax, edx
inc eax
pop edx
ret
_NextInt endp
;****************************************************************
; 初始化所有蛇身结点把前三个置为有效
;****************************************************************
_InitNodes proc
push edi
push edx
push ebx
push ecx
xor edi, edi
@@: xor edx, edx
mov eax, edi
mov ebx, 17h
div ebx; 商是 y 坐标,余数是 x 坐标
xor ecx, ecx
or ecx, edx
inc ecx
shl ecx,8
or ecx, eax
inc ecx
shl ecx,8
or ecx, BODY
shl ecx,8 ; ecx 为结点, ebx 为有效结点列表
; nodeList 数组首元素即蛇尾,最后一个不为0的元素为蛇头
xor ebx, ebx
.if edi <4
or ecx,1
mov ebx, ecx
.endif
mov [offset nodes + edi *4], ecx
mov [offset nodeList + edi *4], ebx
inc edi
.if edi >= 187h
jmp @F
.endif
jmp @B
@@: pop ecx
pop ebx
pop edx
pop edi
ret
_InitNodes endp
;****************************************************************
; 节点构造函数,参数分别是X坐标,Y坐标,类型(食物还是身体),有效标志
;****************************************************************
_CreateNode proc nx, ny, nntype, nInvalid
xor eax, eax
or eax, nx
shl eax,8
or eax, ny
shl eax,8
or eax, nntype
shl eax,8
or eax, nInvalid
ret
_CreateNode endp
;****************************************************************
; 查看指定结点是否在(x, y)
;****************************************************************
_IsNodeAt proc node, x, y
push ebx
push ecx
mov eax, node
mov ebx, eax
mov ecx, eax
shr ebx,24
and ebx, 0ffh
sub ebx, x
shr ecx,16
and ecx, 0ffh
sub ecx, y
.if ecx ==0 && ebx ==0
xor eax, eax
.endif
pop ecx
pop ebx
ret
_IsNodeAt endp
;****************************************************************
; 绘制单个节点
;****************************************************************
_DrawNode proc uses ebx ecx _hDC, hNode
local @stColor: COLORREF
local @hBrush: HBRUSH
local @hOldBrush: HBRUSH
local @stRect: RECT
push ecx
push ebx
mov eax, hNode; 先取标志状态,如果是无效,直接退出
and eax, 000000ffh
.if !eax
jmp @F
.endif
invoke _IsNodeAt, hNode, curX, curY
mov ecx, eax
mov eax, hNode
and eax, 0000ff00h
shr eax,8
.if (eax == BODY) && (ecx ==0)
mov @stColor, 00ffffffh
.elseif eax == BODY
.if bRanColor
invoke _NextInt,255
mov ecx, eax
shl ecx,8
invoke _NextInt,255
or ecx, eax
shl ecx,8
invoke _NextInt,255
or ecx, eax
mov @stColor, ecx
.else
mov @stColor, 000000ffh
.endif
.else
mov @stColor, 0000ff00h
.endif
invoke CreateSolidBrush, @stColor
mov @hBrush, eax
invoke SelectObject, _hDC, @hBrush
mov @hOldBrush, eax; 算出左右要画的地方
mov ecx, hNode
and ecx, 0ff000000h
shr ecx,24
xor eax, eax
mov al, cl
mov bl,20
mul bl
sub eax,4
***************,eaxadd eax,18
****************,eax;算出上下要画的地方
mov ecx, hNode
and ecx, 00ff0000h
shr ecx,16
xor eax, eax
mov al, cl
mov bl,20
mul bl
sub eax,4
**************,eaxadd eax,18
*****************,eax invoke FillRect, _hDC, addr @stRect, NULL
invoke SelectObject, _hDC, @hOldBrush; 狂他妈漏啊……
invoke DeleteObject, @hBrush
@@:
pop ebx
pop ecx
ret
_DrawNode endp
;****************************************************************; 画蛇身,其实就是遍历所有结点画,绘画函数会自己根据结点的状态来选择绘
; 制方式。
;****************************************************************
_DrawBody proc uses ecx edi _hDC
push edi
push ecx
push eax
xor edi, edi
mov ecx, 187h
@@: mov eax, [offset nodeList + edi *4]
.if !eax
jmp @F
.endif
invoke _DrawNode, _hDC, eax
inc edi
loop @B
@@:
pop eax
pop ecx
pop edi
ret
_DrawBody endp
;****************************************************************
; 绘制分数
;****************************************************************
_DrawScore proc _hDC
Local @oldColor: COLORREF
Local @oldBkMode: DWORD
local @szBuffer[128]: BYTE
local @hFont: HFONT
local @hOldFont: HFONT
local @hPen: HPEN
local @hOldPen: HPEN
local @strLen: DWORD
push ebx
invoke wsprintf, offset szScoreBuffer, offset szScore, score; 求字符串长度
xor eax, eax
@@:
mov bl, BYTE ptr [offset szScoreBuffer + eax]
.if bl !=0
inc eax
jmp @B
.endif
mov @strLen, eax
invoke SetBkMode, _hDC, TRANSPARENT
mov @oldBkMode, eax
invoke SetTextColor, _hDC, 0000ffffh
mov @oldColor, eax
invoke CreateFont,14,7,0,0,8, FALSE, FALSE, FALSE, GB2312_CHARSET,
OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,5, DEFAULT_PITCH, NULL
mov @hFont, eax
invoke SelectObject, _hDC, eax
mov @hOldFont, eax
invoke CreatePen, PS_SOLID,1, 00ffffffh
mov @hPen, eax
invoke SelectObject, _hDC, eax
mov @hOldPen, eax
invoke TextOut, _hDC,410,15, offset szScoreBuffer, @strLen
invoke MoveToEx, _hDC,10,10,0
invoke LineTo, _hDC,480,10
invoke LineTo, _hDC,480,360
invoke LineTo, _hDC,10,360
invoke LineTo, _hDC,10,10
invoke SetBkMode, _hDC, @oldBkMode
invoke SetTextColor, _hDC, @oldColor
invoke SelectObject, _hDC, @hOldFont
invoke SelectObject, _hDC, @hOldPen
invoke DeleteObject, @hFont
invoke DeleteObject, @hPen
pop ebx
ret
_DrawScore endp
;****************************************************************
; 获得指定位置上的结点
;****************************************************************
_GetNodeAt proc xLocation, yLocation
push ebx
mov eax, yLocation
dec eax
mov ebx, 17h
mul ebx
add eax, xLocation
dec eax
mov eax, [offset nodes + eax *4]
pop ebx
ret
_GetNodeAt endp
;****************************************************************
; 由传入的X Y 位置查询目标结点的状态(是否激活)
;****************************************************************
_QueryNodeStat proc xLocation, yLocation
invoke _GetNodeAt, xLocation, yLocation
and eax, 000000ffh
ret
_QueryNodeStat endp
;****************************************************************
; 激活或压制一个已处于激活状态的结点; 参数分别是 x 坐标, y坐标, 是否激活的布尔变量
;****************************************************************
_Activate proc xLocation, yLocation, bActivate
push ebx
push edi
mov eax, yLocation
dec eax
mov ebx, 17h
mul ebx
add eax, xLocation
dec eax
mov edi, eax
mov eax, [offset nodes + eax *4]
.if bActivate
or eax, 0000001h
.else
and eax, 0ffffff00h
.endif
mov [offset nodes + edi *4], eax
pop edi
pop ebx
ret
_Activate endp
;****************************************************************
; 下一个食物,总是随机出现。并且不会出现在蛇身上
; 这种实现似乎比较2,更好的方法应该是把所有结点串成两个链表,蛇身链表和非
; 蛇身链表。每次随机地从非蛇身链表里取出结点插入蛇身链表中,这样就不会造成
; 随机生成的位置在蛇身上从而重新生成了。
; 重新生巢呗陨在蛇身将要填充满整个区域时性能急剧下降。
;****************************************************************
_NextFood proc uses ebx
invoke _NextInt,17
mov foodY, eax
invoke _NextInt,23
mov foodX, eax
invoke _QueryNodeStat, foodX, foodY
.if eax
invoke _NextFood
.endif
invoke _CreateNode, foodX, foodY, FOOD,1
mov food, eax
ret
_NextFood endp
;****************************************************************
; 往队列头加一个结点,刚吃了一顿或走了一步后都会调用此函数。
; 第一个参数是要加入的结点,第二个是指示是否移除队列尾。正常移动时需要
; 在队列头加结点的同时移除队列尾,以达到好像在移动的假象……
;****************************************************************
_AddBody proc node, bRmvTail
push edi
push ebx
push ecx; 如果是刚吃的,先把类型改成 BODY
mov eax, node
or eax, 00000100h
xor edi, edi
@@:
mov ebx, [offset nodeList + edi *4]
.if ebx !=0
inc edi
jmp @B
.endif
mov [offset nodeList + edi *4], eax
; 如果要移除队列尾,则先把队列尾的激活状态压下去,然后集体左移一个索引位置
; 此时edi里保存着队列应有的长度
.if bRmvTail; 取第一个元素,这是队列头,先反激活它
mov eax, [nodeList]
mov ebx, eax
and ebx, 0ff000000h
shr ebx,24
mov ecx, eax
and ecx, 00ff0000h
shr ecx,16
invoke _Activate, ebx, ecx, FALSE; 然后移动这个队列,把后面的都左移
mov ecx, edi
xor edi, edi
@@: mov eax, [offset nodeList + edi *4 +4]
mov [offset nodeList + edi *4], eax
inc edi
loop @B
mov [offset nodeList + edi *4],0
.endif
pop ecx
pop ebx
pop edi
ret
_AddBody endp
;****************************************************************
; 吃掉食物,吃掉时候分数增加,并且生成下一个食物
;****************************************************************
_PieFromSky proc
mov eax, score
add eax,10
mov score, eax
mov eax, eatCounts
.if eax !=3
inc eatCounts
.else
mov eax, speed
.if eax >1
dec speed
.endif
mov eatCounts,0
.endif
invoke _GetNodeAt, foodX, foodY
invoke _AddBody, eax, FALSE
invoke _NextFood
ret
_PieFromSky endp
;****************************************************************
; 新游戏,初始化各种状态
;****************************************************************
_NewGame proc
invoke _InitNodes
invoke _NextFood
mov bTurnPending, FALSE
mov isPaused,0
mov isAlive,1
mov score,0
mov speed,8
mov timerCounts,0
mov eatCounts,0
mov curX,4
mov curY,1
mov direction, RIGHT
ret
_NewGame endp
;****************************************************************
; 蛇身移动
;****************************************************************
_Move proc
Local @nextX: DWORD
Local @nextY: DWORD
push ebx
push curX
push curY
pop @nextY
pop @nextX
mov bTurnPending, FALSE
.if direction == RIGHT
inc @nextX
.elseif direction == DOWN
inc @nextY
.elseif direction == LEFT
dec @nextX
.elseif direction == UP
dec @nextY
.endif
.if (@nextX ==0) || (@nextX >23) || (@nextY ==0) || (@nextY >17)
mov isAlive,0
jmp @F
.endif
invoke _QueryNodeStat, @nextX, @nextY
.if eax
mov isAlive,0
jmp @F
.endif
mov eax, foodX
mov ebx, foodY
.if (@nextX == eax) && (@nextY == ebx)
invoke _PieFromSky
.endif; 头的处理,下一个位置即将激活
invoke _Activate, @nextX, @nextY,1
push @nextX
push @nextY
pop curY
pop curX; 把新头加入队列头,并指示移除队列尾
invoke _GetNodeAt, curX, curY
版权声明:本文标题:matlab各种游戏编程大全-俄罗斯方块-贪吃蛇-拼图-五子棋-黑白棋-华 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/free/1709281799h541878.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论