【MATLAB小游戏】养鱼

【MATLAB小游戏】养鱼

by 今天不飞了

疫情在家闲着无聊写的,游戏本身没有可玩性,仅为给大家分享思路。
MATLAB可以设计一些低性能的游戏。


在这里插入图片描述

视频链接《因为疫情被封控十天后,开始用MATLAB养鱼玩儿》

代码

function simple_fish(n)
close all; clc
global flag
% 界面
flag = 0;
figure('position',[0 30 1600 840],'color','w','WindowButtonMotionFcn',@currentPt,'menubar','none');
set(gcf,'WindowButtonDownFcn',@ButtonDownFcn);
set(gcf,'KeyPressFcn',@KeyPressFcn);
IpSld = uicontrol('style','slider','Units','normalized',...
    'position',[180 992.5 300 20]/1080,'min',0.01,'max',10,'Value',1.5,'Visible',0);
InSld = uicontrol('style','slider','Units','normalized',...
    'position',[610 992.5 300 20]/1080,'min',0,'max',5,'Value',4.1,'Visible',0);
folf = uicontrol('style','togglebutton','Units','normalized',...
    'position',[.85 .85 .09 .025],'min',0,'max',1,'Value',1,'String','Follow Fish','Visible',0);
bait = uicontrol('style','togglebutton','Units','normalized','callback',@danger,...
    'position',[.85 .8 .09 .025],'min',0,'max',1,'Value',0,'String','Put Bait','Visible',0);
goal = uicontrol('style','togglebutton','Units','normalized','callback',@food,...
    'position',[.85 .4 .09 .025],'min',0,'max',1,'Value',0,'String','Shark Goal','Visible',0);
tax = axes('position',[.05 .05 .9 .85],'visible','off'); hold all;
axis(tax,[-10 10 -10 10]*2);
ax = axes('position',[.05 .05 .9 .85],'xcolor','none','ycolor','none'); hold all;
axis(ax,[-10 10 -10 10]*2); grid on; box off;
colormap(ax,'hot');
caxis(ax,[.5 2]);

%% 参数
total_time = 1e6;
dt = 5e-2;
% 数量
if nargin<1 || isempty(n)
    n = 50; 
end
If = 1e-2; 
attrS = 1; 
alpha = rand(n,1)*2*pi; % 初始方向
r = 10*randn(n,2); % 初始位置
state = [r alpha]; % 状态
fishL = .6; fishH = .1;
% 形状
xfish = [-.5, -.25,  0, .1, .125, .1, 0,  -.25]'*1;
yfish = [0, .075, .1, .05, 0, -.05, -.1, -.075]'/2*1;
% 可视化
pth = patch(xfish + zeros(1,n), yfish + zeros(1,n),zeros(n,1),'edgecolor','none');
baitx = []; baity = [];
baith = plot(0,0,'k+','markersize',18,'linewidth',2,'visible','off');
goalx = []; goaly = [];
goalh = plot(0,0,'bo','markersize',18,'linewidth',2,'visible','off');
cp = [];
replD = fishL*4; 
replS = 200; 

%% 开始养鱼
t = -dt;
tmax = 100;
while t<tmax
    t = t + dt;    
    if isvalid(ax)
        xalim = get(ax,'xlim');
        yalim = get(ax,'ylim');
    else
        break
    end    
    % 属性
    Ip = get(IpSld, 'Value'); 
    In = get(InSld, 'Value');     
    % 方向
    e = [cos(state(:,3)) sin(state(:,3))];
    dTri = delaunay(state(:,1:2));
    vn = sparse(dTri,dTri(:,[2 3 1]),1);
    vn = vn | vn';    
    listI = repmat(1:n,1,n);
    ns = listI(vn);
    nn = sum(vn);
    nnmax = max(nn);
    % 鱼群模式
    neighborI = full(sparse(nn+1,1:n,n+1));
    neighborI = cumsum(neighborI(1:end-1,:),1); 
    neighborI(neighborI==0) = ns;
    neighborI = neighborI';
    stateA = [state; nan(1,3)];
    phi = reshape(stateA(neighborI,3),n,nnmax) - state(:,3);
    rho1 = reshape(stateA(neighborI,1),n,nnmax) - state(:,1);
    rho2 = reshape(stateA(neighborI,2),n,nnmax) - state(:,2);
    rhon = sqrt(rho1.^2 + rho2.^2);
    theta = getangle(state(:,3),rho1,rho2,rhon);
    minDist = nanmin(rhon,[],2);
    w_vision = nansum((Ip*sin(phi) + rhon.*sin(theta)).*(1 + cos(theta)),2)./nansum(1 + cos(theta),2);
    % 目标
    if ~isempty(baitx) 
        for bi = 1:numel(baitx)
            xb = baitx(bi); yb = baity(bi);
            attrNum = min(n,5); 
            dv = [xb,yb] - state(:,1:2);
            [distf,sortf] = sort(sqrt(sum(dv.^2,2)));
            attrD = (distf(attrNum) + distf(1))/2; 
            for j = 1:attrNum
                attrf = sortf(j);
                w_bait = getangle(state(attrf,3),dv(attrf,1),dv(attrf,2),distf(j));
                w_vision(attrf) = (w_vision(attrf)*exp(attrS*(distf(j) - attrD)) + ...
                    w_bait)/(1 + exp(attrS*(distf(j) - attrD)));
            end
        end
    end        
    if ~isempty(cp) 
        dcpv = cp(1:2) - state(:,1:2);
        dcp = sqrt(sum(dcpv.^2,2));
        w_cp = getangle(state(:,3),-dcpv(:,2),-dcpv(:,1),dcp);
        w_vision = (w_vision + w_cp.*exp(replS*(replD - dcp)))./(1 + exp(replS*(replD - dcp)));
    end
    w_noise = In*sqrt(dt)*randn(n,1);    
    otherI = repmat(1:n,1,n);
    otherI(1:(n+1):end) = [];
    otherI = reshape(otherI,n,n-1);    
    dZ = state(:,1) + 1i*state(:,2) - reshape(state(otherI,1) + 1i*state(otherI,2),n,n-1);
    o_di = reshape(state(otherI,3),n,n-1);    
    U_complex = sum(exp(1i*o_di)./dZ.^2,2)/pi;
    w_complex = sum(imag(exp(1i*(2*state(:,3)+o_di))./dZ.^3),2)*2/pi;    
    collisionAvoid = 1./(1 + exp((fishH - minDist)/fishH*10));
    U = [real(U_complex), -imag(U_complex)]*If.*collisionAvoid;
    w_hydro = w_complex*If.*collisionAvoid;
    theta_dot = w_vision + w_noise + w_hydro;
    rdot = e + U;    
    % 位移
    state = state + [rdot theta_dot]*dt;     
    set(pth,'XData',xfish.*e(:,1)' - yfish.*e(:,2)' + state(:,1)',...
        'YData',xfish.*e(:,2)' + yfish.*e(:,1)' + state(:,2)','CData',sum(rdot.^2,2));    
    % 中轴
    if get(folf,'value')
        axis(ax,[xalim yalim] + [(mean(state(:,1))-mean(xalim))*[1 1],...
            (mean(state(:,2)) - mean(yalim))*[1 1]]);
    end
    drawnow;
end
 % 没想好写什么
    function currentPt(~,~)

    end
    % 吓唬
    function danger(~,~)
        if get(bait,'value') 
            [xb,yb] = ginput(1);
            baitx = [baitx xb]; baity = [baity yb];
            set(bait,'value',0);
            set(baith,'xdata',baitx,'ydata',baity,'visible','on');
        end
    end
    % 投喂
    function food(~,~)
        if get(goal,'value') 
            [xb,yb] = ginput(1);
            goalx = xb; goaly = yb;
            set(goal,'value',0);
            set(goalh,'xdata',goalx,'ydata',goaly,'visible','on');
        end
    end
    % 鼠标点击
    function ButtonDownFcn(~,~)
        pt = get(gca,'CurrentPoint');
        xb = pt(1,1);
        yb = pt(1,2);
        if flag
            baitx = xb; baity = yb;
        else
            cp = [xb,yb];
        end
    end
    % 键盘点击
    function KeyPressFcn(~,~)
       pt = get(gcf,'CurrentCharacter');
        if strcmpi(pt,'r')
            flag = 1-flag;
            if flag
                disp('投喂模式')
            else
                disp('驱散模式')
            end
        end
        if strcmpi(pt,'c')
            baitx = [];
            baity = [];
            cp = [];
        end
        if strcmpi(pt,'q')
            disp('锁定视角')
            tmp = get(folf,'Value');
            set(folf,'Value',1-tmp)
        end
    end
end

% 计算偏移角的
function [theta] = getangle(phi,rhox,rhoy,rhom)
if nargin < 4, rhom = sqrt(rhox.^2 + rhoy.^2); end
rhox = rhox./rhom;
rhoy = rhoy./rhom;
ex = cos(phi);
ey = sin(phi);
sgn = sign(ex.*rhoy - ey.*rhox);
sgn(sgn == 0) = 1;
theta = sgn.*acos(ex.*rhox + ey.*rhoy);
end


其他

大概没有什么bug

  • 9
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值