- /
-
danger lizard
on 22 Oct 2024
- 25
- 170
- 0
- 0
- 1751
Cite your audio source here (if applicable):
Crunch: Eating a carrot.wav by Reenen007 -- https://freesound.org/s/538682/ -- License: Attribution 4.0
Final audio was mixed to match the animation by MATLAB.
drawframe(1);
Write your drawframe function below
function drawframe(f)
% Compute a position on the path of our critter
AF=@(t)[ sinpi(t) sinpi(t)*cospi(t)*2 ]*10;
Q=f/96*2;
A=AF(Q);
persistent LH S BP fpv
if f==1
% Segments of our creature - defaults just to get started
S=ones(18,2)*-10;
S(:,2)=-18:-1;
end
% Follow Radii - distances between spine segments
%FR = [.6
% 1.2
% 1.2
% 1.2
% 1.2
% 1.2
% 1.2
% .6
% .6
% .6
% .6
% .6
% .6
% .6
% .6
% .6
% .6
% .6];
B=[.6 1.2];
FR=B('122222211111111111'-'0')';
% Body Radii - Sizes of body at that spine segment
BR=[.7
1
.5
1
1
1
(1:-.1:.2)'
.2
.2
.1];
% Leg Data
LS=[4 7];% Segments where legs attached
% Following Vectors
FV=0;
function DF()% do follow
% Follow the anchor point (point 1) by making sure
% all parts of the spine are the correct length and follow
% the previous nodes
FV=dn(S(1,:),S(2,:));
for k=2:size(S,1)
FV(k,:)=dn(S(k-1,:),S(k,:));
S(k,:)=FV(k,:)*FR(k-1)+S(k-1,:);
end
end
function verts=SP(seg, LR)% side points
% Compute pts on the left & right side of a body segment.
% Useful for eyes, legs, fins, etc
FV(:,3)=0;% 3 dimensions
si=[seg-1 seg];% segment indices so there is a direction
c=cross(FV(si,:),repmat([0 0 1],2,1));% Find the 2 pts
c=c./vecnorm(c,2,2).*BR(si);% normalize the adjust by the body radii
c=c*LR;% LR is length from center as a ratio of body size.
% Final vertices are on the left & right, and offset around the segment
verts=[c(2,1:2);-c(2,1:2)]+S(seg,:);
end
if f==1
DF();
% Get lizard to walk around the back half of our walking shape
% so when the video loops it appears seamless.
for a=linspace(1.5,2,10)
S(1,:)=AF(a);
DF();
end
% Setup history of the feet/legs
LH=[SP(LS(1),2)
SP(LS(2),2)];
% Footprints vector init to initialized histor
fpv=LH;
fpv(:,3)=1;
end
S(1,:)=A;% Move anchor point for critter
DF();% Make critter move to new point.
%% DRAWING
%% Footprints
fpv(:,3)=fpv(:,3)*.9;
fpv(fpv(:,3)<.1,:)=[]; % Clear out old footprints.
scatter(fpv(:,1),fpv(:,2),42,[.2 .4 .6],'*','AlphaData',fpv(:,3),'MarkerEdgeAlpha','flat');
hold on
%% LEGS
% Origin for each body segment attached to legs
o1=S(LS(1),1:2);
o2=S(LS(2),1:2);
O=[o1
o1
o2
o2];
% New target locations by calling side points fcn
T=[SP(LS(1)-1,4)
SP(LS(2)-1,2)];
% Compute how far away we are for each historical foot
d=vecnorm(LH-O,2,2);
% Update any feet that can stay where they are to be historical posn
% ie - the foot doesn't move, but leg stretches to keep foot there.
H=d<3.1;
T(H,:)=LH(H,:);
% Update footprint history with any newly moved feet
% NOTE: IK seems to have rounding errors so footprints don't always
% line up where the legs go. Close enough for the illusion to work.
tmp=T(~H,:);
tmp(:,3)=1;
fpv=[tmp
fpv];
% Upate history of where our feet are
LH=T;
% Compute geometry to draw derpy legs
% IK is an inverse kinematic algorithm (see fcn below)
V=[];
D=[-1
1
1
-1];
for j=1:4
V=[V%#ok
nan nan
IK(S(LS(floor((j+1)/2)),:),T(j,:),D(j))];
end
% Plot the legs under everything else
plot(V(:,1),V(:,2),'col','#03ac13','linew',8);
% Gecko feet with big toes
plot(V(4:4:end,1),V(4:4:end,2),'*','col','#03ac13','linew',3,'markers',14);
%% Bug to Eat!
% After legs but below the body so our critter can eat it.
bp=AF(mod(floor((Q+.2)*2)/2+.25,2));
text(bp(1),bp(2),'🕷','fontsi',24,'hor','cent','rot',360*rand);
% %% Audio Generator
% % Whenever a foot moves, make a footfall sound.
% if any(~H([1 3]))
% AS.event(1,0);
% end
% if any(~H([2 4]))
% AS.event(2,0);
% end
% % Nom Nom the bug when the bug moves to next location.
% if ~isempty(BP) && any(BP~=bp)
% AS.event(3,0);
% end
% BP=bp;
%% Body Graphics as polyshape
% Create a bunch of polyshape buffers based on convex hulls of
% Adjacent points in the spine
ps=polyshape;
for i=1:18
ps(i)=polybuffer(S(i,:),'point',BR(i));
if i>1
pseg(i-1)=convhull(union(ps(i-1:i))); %#ok
end
end
plot(union(pseg),'EdgeC','#028a0f','FaceColor','#23421d','FaceA',1,'linewi',2);
%% Racing Stripe
plot(S(:,1),S(:,2),'-.','col','#028a0f','linew',6);
%% Eye Graphic
EV=SP(2,.8);
plot(EV(:,1),EV(:,2),'.','col','#f50505','markers',25);
% Setup Axes
axis([-12 12 -12 12])
set(gca,'pos',[0 0 1 1],'vis','off');
hold off
end
function S = IK(A, D, S)%Inverse kinematic
% Do some inverse kinematics to position the feet of the lizard.
% I found an algorithm here, and trimmed it down to exclude all the special cases
% which our foot history algorithm prevents us from hitting. I also
% folded all the known constants (like leg lengths) making this very short.
% https://motion.cs.illinois.edu/RoboticSystems/InverseKinematics.html
XD=D-A;
%L1=2; % inner leg segment length
%L2=1; % outer leg segment length
% c2 is the cos of q2, where q2 is the angle at the elbow
% i.e. c2 is a length on a unit circle
%c2=(norm(XD)^2-L1^2-L2^2)/(2*(L2*L1));
c2=(norm(XD)^2-5)/4;
% Assume no corner cases will be encountered in the lizard.
q2=S*real(acos(c2));
%q1=atan2(XD(2),XD(1))-atan2(L2*sin(q2),L1+L2*cos(q2));
q1=atan2(XD(2),XD(1))-atan2(sin(q2),2+cos(q2));
P1=2*[cos(q1),sin(q1)];
S=[0 0
P1
P1+[cos(q2+q1),sin(q2+q1)]]+A;
end
function N=dn(p,t)
% Compute the normalized vector representing normal from POS toward TGT
d=t-p;
N=d./vecnorm(d,2,2);
end