数学实验课随便写的
原理
通过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