Matlab坦克大战

原创
2020/09/17 13:20
阅读数 48

数学实验课随便写的

原理

通过Action序列产生(打子弹,靠近玩家,往X方向移动)
执行Action
电脑Agent玩家追踪使用切比雪夫距离
Dist=Max(|x_2-x_1 |,|y_2-y_1 |) 式中
x1,y1为当前电脑坦克坐标
x2,y2为当前玩家坦克坐标
当随机出Action以后需要靠近玩家,则计算切比雪夫距离,往降低切比雪夫距离的方向移动电脑坦克
Move=Min(Max(|x_2-x_1 |,|y_2-y_1 |))

运行结果

主界面,按下空格开始游戏

红方为Player1控制键为↑↓←→,蓝方为Player2,控制键为wasd
绿色为射出的子弹(玩家子弹碰触也会误杀队友)

附代码

主程序

function varargout = main(varargin)

gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
    'gui_Singleton',  gui_Singleton, ...
    'gui_OpeningFcn', @main_OpeningFcn, ...
    'gui_OutputFcn',  @main_OutputFcn, ...
    'gui_LayoutFcn',  [] , ...
    'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before main is made visible.
function main_OpeningFcn(hObject, eventdata, handles, varargin)
global Tank_1;
Tank_1=Tank([100,200,10,10],true);
global Tank_2;
Tank_2=Tank([100,100,10,10],true);

global PlayerBooms;
PlayerBooms=[];

global EnemyBooms;
EnemyBooms=[];

global GameLevel;
GameLevel=1;

%随机敌人
global Enemy;
Enemy=[Tank([double(int32(rand(1,1)*490)),double(int32(rand(1,1)*490)),10,10],false)];

% Choose default command line output for main
handles.output = hObject;
%定时器
handles.ht=timer;
set(handles.ht,'ExecutionMode','FixedRate');
set(handles.ht,'Period',0.5);
set(handles.ht,'TimerFcn',{@UpdateWindow,handles});
%start(handles.ht);
% Update handles structure
guidata(hObject, handles);

% UIWAIT makes main wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = main_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;




function figure1_WindowKeyPressFcn(hObject, eventdata, handles)
%% 按键操作
%disp(abs(eventdata.Character));
global Tank_1;
global Tank_2;
global PlayerBooms;
if ~strcmp(handles.ht.Running,'off')
    switch abs(eventdata.Character)
        %红上下左右
        case 119 %上
            Tank_1.Direct=1;
            Tank_1.Pos(2)=Tank_1.Pos(2)+10;
        case 115 %下
            Tank_1.Direct=2;
            Tank_1.Pos(2)=Tank_1.Pos(2)-10;
        case 97 %左
            Tank_1.Direct=3;
            Tank_1.Pos(1)=Tank_1.Pos(1)-10;
        case 100 %右
            Tank_1.Direct=4;
            Tank_1.Pos(1)=Tank_1.Pos(1)+10;
        case 101 %开火
            PlayerBooms=[PlayerBooms,Tank_1.createBoom()];
            
            %蓝左右上下
        case 28 %左
            Tank_2.Direct=3;
            Tank_2.Pos(1)=Tank_2.Pos(1)-10;
        case 29 %右
            Tank_2.Direct=4;
            Tank_2.Pos(1)=Tank_2.Pos(1)+10;
        case 30 %上
            Tank_2.Direct=1;
            Tank_2.Pos(2)=Tank_2.Pos(2)+10;
        case 31 %下
            Tank_2.Direct=2;
            Tank_2.Pos(2)=Tank_2.Pos(2)-10;
        case 47 %开火
            PlayerBooms=[PlayerBooms,Tank_2.createBoom()]
        case 32 %停止定时器
            disp('暂停游戏');
            stop(handles.ht);
            
    end
else
    switch abs(eventdata.Character)
        case 32 %停止定时器
            disp('开始游戏');
            start(handles.ht)
    end
end

%Tank_1(1)=Tank_1(1)+10;
%Tank_2(1)=Tank_2(1)-10;



function UpdateWindow(hObject, eventdata, handles)
global Tank_1;
global Tank_2;
global PlayerBooms;
global EnemyBooms;
global Enemy;
global GameLevel;

cla(handles.axes1,'reset');
if isempty(Enemy)
    GameLevel=GameLevel+1;
    for i=1:GameLevel
        Enemy=[Enemy Tank([double(int32(rand(1,1)*490)),double(int32(rand(1,1)*490)),10,10],false)];
    end
end
%% 敌人坦克策略
Enemy=Agent(Enemy,[Tank_1,Tank_2],490,0);
%敌人开火
for i=1:length(Enemy)
    action=max(int32(rand(1,1)*10));
    if action>8
        EnemyBooms=[EnemyBooms,Enemy(i).createBoom()];
    end
end
for i=1:length(Enemy)
    rectangle(handles.axes1,'Position',Enemy(i).Pos,'Curvature',[1,1],  'FaceColor','y')
end
%% 敌人中弹判断
outPlayerBooms=zeros(1,length(PlayerBooms));
outEnemy=zeros(1,length(Enemy));
for i=1:length(PlayerBooms)
    for j=1:length(Enemy)
        point_1=[PlayerBooms(i).Pos(1),PlayerBooms(i).Pos(2)];
        point_2=[Enemy(j).Pos(1),Enemy(j).Pos(2)];
        distance=norm(point_1-point_2);
        if abs(distance)<10
            outPlayerBooms(i)=1;
            outEnemy(i)=1;
            break;
        end
    end
end
try
    PlayerBooms(outPlayerBooms==1)=[];
    Enemy(outEnemy==1)=[];
catch
    disp(['删除错误',num2str(length(outPlayerBooms)),'  ',num2str(outEnemy)]);
    disp(Enemy)
end
%% 玩家坦克移动
if Tank_1.HP>0
    rectangle(handles.axes1,'Position',Tank_1.Pos,'Curvature',[1,1],  'FaceColor','r')
end
if Tank_2.HP>0
    rectangle(handles.axes1,'Position',Tank_2.Pos,'Curvature',[1,1],  'FaceColor','b')
end
%% 玩家中弹判断
outEnemyBooms=zeros(1,length(EnemyBooms));
for i=1:length(EnemyBooms)
    point_1=[EnemyBooms(i).Pos(1),EnemyBooms(i).Pos(2)];
    point_2=[Tank_1.Pos(1),Tank_1.Pos(2)];
    distance_1=norm(point_1-point_2);
    if distance_1<5
        outEnemyBooms(i)=1;
        Tank_1.HP=Tank_1.HP-10;
    end
    point_1=[EnemyBooms(i).Pos(1),EnemyBooms(i).Pos(2)];
    point_2=[Tank_2.Pos(1),Tank_2.Pos(2)];
    distance_2=norm(point_1-point_2);
    if distance_2<5
        outEnemyBooms(i)=1;
        Tank_2.HP=Tank_2.HP-10;
    end
end
EnemyBooms(outEnemyBooms==1)=[];
handles.text2.String=['Player1 HP:',num2str(Tank_1.HP)];
handles.text3.String=['Player2 HP:',num2str(Tank_2.HP)];

%% 子弹移动
outPlayerBooms=zeros(1,length(PlayerBooms));
for i=1:length(PlayerBooms)
    rectangle(handles.axes1,'Position',PlayerBooms(i).Pos,'Curvature',[1,1],  'FaceColor','g')
    %if Booms(i).Pos(1)>500 || Booms(i).Pos(i)<0 || Booms(i).Pos(2) >500 || Booms(i).Pos(2)<0
    if PlayerBooms(i).Pos(1)<=490 && PlayerBooms(i).Pos(1)>=0 && PlayerBooms(i).Pos(2) <=490 && PlayerBooms(i).Pos(2)>=0
        PlayerBooms(i)=PlayerBooms(i).updatePos();
    else
        outPlayerBooms(i)=1;
    end
end
PlayerBooms(outPlayerBooms==1)=[];

outEnemyBooms=zeros(1,length(EnemyBooms));
for i=1:length(EnemyBooms)
    rectangle(handles.axes1,'Position',EnemyBooms(i).Pos,'Curvature',[1,1],  'FaceColor','y')
    %if Booms(i).Pos(1)>500 || Booms(i).Pos(i)<0 || Booms(i).Pos(2) >500 || Booms(i).Pos(2)<0
    if EnemyBooms(i).Pos(1)<=490 && EnemyBooms(i).Pos(1)>=0 && EnemyBooms(i).Pos(2) <=490 && EnemyBooms(i).Pos(2)>=0
        EnemyBooms(i)=EnemyBooms(i).updatePos();
    else
        outEnemyBooms(i)=1;
    end
end
EnemyBooms(outEnemyBooms==1)=[];
%%
set(handles.axes1,'XLim',[0,500]);
set(handles.axes1,'YLim',[0,500]);


% --- Executes when user attempts to close figure1.
function figure1_CloseRequestFcn(hObject, eventdata, handles)
% hObject    handle to figure1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: delete(hObject) closes the figure
stop(handles.ht);
delete(hObject);

坦克类Tank.m

classdef Tank
    
    properties
        Pos;
        Player;
        HP=100;
        Level=1;
        Direct=1;
        Speed=10;
    end
    
    
    methods
        function obj = Tank(pos,player)
            assert(isa(player,'logical'));
            assert(isa(pos,'numeric'));
            obj.Pos = pos;
            obj.Player=player;
        end
        function dead = isDead(obj)
            if obj.HP<=0
                dead=true;
            else
                dead=false;
            end
        end
        function obj=updatePos(obj)
            % 1  2   3  4
            % 上 下  左 右
            switch(obj.Direct)
                case 1
                    obj.Pos(2)=obj.Pos(2)+obj.Speed;
                case 2
                    obj.Pos(2)=obj.Pos(2)-obj.Speed;
                case 3
                    obj.Pos(1)=obj.Pos(1)-obj.Speed;
                case 4
                    obj.Pos(1)=obj.Pos(1)+obj.Speed;
            end
        end
        function boom = createBoom(obj)
           boom=Boom(obj.Pos,obj.Direct,obj.Level);
        end
    end
end

敌方坦克策略Agent.m

function [agent] = Agent(agent_now,player_now,max_map,min_map)
%敌人坦克移动
for i=1:length(agent_now)
    now_tank=agent_now(i);
    
    max_direct=zeros(1,length(player_now));
    max_distance=zeros(1,length(player_now));
    for j=1:length(player_now)
       [direct,distance]=Mindirection(agent_now(i).Pos,player_now(j).Pos); 
       max_direct(j)=direct;
       max_distance(j)=distance;
    end
    action=max(int32(rand(1,1)*10));
    if action>5
        %往距离最近玩家方向移动
       [value,min_direct_index]=min(max_distance);
       now_tank.Direct=max_direct(min_direct_index);
    else
        [value,random_direct]=max(rand(1,4));%随机一个方向移动
        now_tank.Direct=random_direct;
    end
    now_tank=now_tank.updatePos();
    if now_tank.Pos(1)<=max_map && now_tank.Pos(1)>=min_map && now_tank.Pos(2) <=max_map && now_tank.Pos(2)>=min_map
        agent_now(i)=now_tank;
    end
end
agent=agent_now;

子弹类Boom.m

classdef Boom
    
    properties
        Pos;
        Direct;
        Power;
        Speed=20;
    end
    
    methods
        function obj = Boom(pos,direct,power)
            obj.Pos=[pos(1)+pos(3)/4,pos(2)+pos(4)/4,5,5];
            obj.Direct=direct;
            obj.Power=power;
        end
        
        function obj=updatePos(obj)
            % 1  2   3  4
            % 上 下  左 右
            switch(obj.Direct)
                case 1
                    obj.Pos(2)=obj.Pos(2)+obj.Speed;
                case 2
                    obj.Pos(2)=obj.Pos(2)-obj.Speed;
                case 3
                    obj.Pos(1)=obj.Pos(1)-obj.Speed;
                case 4
                    obj.Pos(1)=obj.Pos(1)+obj.Speed;
            end
        end
    end
end

切比雪夫距离函数Mindirection.m

function [direct,distance]=Mindirection(pos_1,pos_2)
diff_x=pos_1(1)-pos_2(1);
diff_y=pos_1(2)-pos_2(2);
if abs(diff_x)>abs(diff_y)
    distance=diff_x;
    if diff_x>0
        direct=3;
    else
        direct=4;
    end
else
    distance=diff_y;
    if diff_y>0
        direct=2;
    else
        direct=1;
    end
end
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部