How can you move a plot using a keyboard input?

I have asked a similar question before, but I think it would be easier to find an answer since I changed my code a bit. I have a plot that contains a circle. I want to change move the center of the circle using keyboard input.
function h = circle(xCenter,yCenter,radius)
hold on
th = 0:pi/50:2*pi;
xunit = radius * cos(th) + xCenter;
yunit = radius * sin(th) + yCenter;
h = plot(xunit, yunit);
hold off
end
xCenter = 330;
yCenter = 255;
radius = 16;
%ship = viscircles([xCenter, yCenter], radius, 'Color', 'c');
%My previous code used viscircle but I realized that plot works
%just fine with my code. also i think it is easier to get
%numerical data using plot
S.ship = circle(xCenter, yCenter, radius);
set(gcf(), 'KeyPressFcn', @fig_kpfcn);
%can you set a plot as a figure? I have a background image
%right now that the figure initially was set to. this part of
%the code occurs when the a button is pressed and the figure
%changes background and gets rid of all existing buttons.
%However, it is still the same figure. i'm using gcf() cuz i
%don't know what else to use.
hold off
guidata(S.ship,S);
%this is where i'm not sure if i coded everything correctly. I followed a previous mathworks answer page
%https://www.mathworks.com/matlabcentral/answers/8790-reading-arrow-key-input?s_tid=srchtitle
%but i don't know if i understood it completely. Same for the
%code below. i did almost directly copy the code, but i just
%wanted to make sure it works before changing any numbers.
function [] = fig_kpfcn(varargin)
% Figure (and pushbutton) keypressfcn
S = guidata(H);
P = get(S.ship,'position');
%set(s.h, 'KeyPressFcn', E.Key)
switch E.Key
case 'rightarrow'
set(S.ship,'pos',P+[5 0 0 0])
case 'leftarrow'
set(S.ship,'pos',P+[-5 0 0 0])
case 'uparrow'
set(S.ship,'pos',P+[0 5 0 0])
case 'downarrow'
set(S.ship,'pos',P+[0 -5 0 0])
otherwise
end
Any help would be appreciated.

 Respuesta aceptada

Voss
Voss el 15 de Abr. de 2022
Editada: Voss el 15 de Abr. de 2022
I think you're right that plot is probably easier to work with than viscircles, and your circle function appears to work as-is.
The main thing to fix in your code is the definition of the function fig_kpfcn, which had been adapted from the other answer. That answer was about moving a figure by setting its 'Position' property, and the analogous thing for a line object (such as the plotted circle here) would be to set its 'XData' and 'YData' properties. See my adapted fig_kpfcn below.
In particular, note that fig_kpfn has two input arguments: H - the figure, and E - the so-called "event data" (both of which appeared in the other answer but disappeared in your code).
Without seeing exactly how the code you've shared fits in with the rest of the GUI, I can't say for sure you could copy and paste this code into yours and have it work without modification, but maybe seeing fig_kpfcn here is sufficient for you to see what you need to do in your code to get it to work.
xCenter = 330;
yCenter = 255;
radius = 16;
S.ship = circle(xCenter, yCenter, radius);
set(gcf(), 'KeyPressFcn', @fig_kpfcn);
guidata(S.ship,S);
function [] = fig_kpfcn(H,E)
% Figure (and pushbutton) keypressfcn
S = guidata(H);
switch E.Key
case 'rightarrow'
set(S.ship,'XData',get(S.ship,'XData')+5);
case 'leftarrow'
set(S.ship,'XData',get(S.ship,'XData')-5);
case 'uparrow'
set(S.ship,'YData',get(S.ship,'YData')+5);
case 'downarrow'
set(S.ship,'YData',get(S.ship,'YData')-5);
end
end
function h = circle(xCenter,yCenter,radius)
hold on
th = 0:pi/50:2*pi;
xunit = radius * cos(th) + xCenter;
yunit = radius * sin(th) + yCenter;
h = plot(xunit, yunit);
hold off
end

6 comentarios

Theres not much in the GUI besides this, the figure, buttons, and the ability to close the game. It didn't work when I copy and pasted, which was expected. I did see that it worked when not implemented in my code. I'll show bits and pieces of the code.
%the figure that holds the game.
S.fig = figure('units','pixels',... % Units of measurement
'name','ISOLATION',... % Name of Game
'menubar','none',... % No menu bar
'numbertitle','off',... % No number title (Figure 1, etc.)
'Resize','off',...
'position',[200 200 640 480],... % Position of game
'color',fig_clr,... % color of background
'keypressfcn',@fig_kpfcn,...% key pressed
'closereq',@fig_clsrqfcn,...% close the game
'busyaction','cancel',...
'renderer','opengl',...
'BackingStore','on',...
'windowbuttondownfcn',@fig_wbdfcn);
% theres some code that just makes buttons and makes axes invisible. Now
% I'm thinkin about it, it might be the axes code.
S.axs = axes('units','pix',...
'position','default',...
'ycolor',fig_clr,...
'xcolor',fig_clr,...
'color',fig_clr,...
'xtick',[],'ytick',[],...
'xlim',[-.1 7.1],...
'ylim',[-.1 7.1],...
'visible','off');
%%the code i put in the question is code that happens when i press the
%%start button.
function [] = pbtStart_call(varargin)
% will also be used for pause and continue buttons (switch st8ment)
switch get(S.pbtStart,'string')
case 'Start'
set(S.pbtStart,'string','Pause',...
'position',[500 45 100 50],...
'fontsize',14); % Changle pushbutton label.
set(S.pbtLDB,'Visible','off','Enable','off');
set(S.pbtLore,'Visible','off','Enable','off');
set(S.txt,'Visible','off');
play_ISOL; % Initiate Gameplay.
end
end
function [] = play_ISOL()
S.currLVL = 1;
S.currSCR = 0;
function h = circle(xCenter,yCenter,radius)
hold on
th = 0:pi/50:2*pi;
xunit = radius * cos(th) + xCenter;
yunit = radius * sin(th) + yCenter;
h = plot(xunit, yunit, "Color", 'c', 'LineWidth', 2);
hold off
end
xCenter = 330;
yCenter = 255;
radius = 16;
%ship = viscircles([xCenter, yCenter], radius, 'Color', 'c');
S.ship = circle(xCenter, yCenter, radius);
set(gcf(), 'KeyPressFcn', @fig_kpfcn);
guidata(S.ship,S);
function [] = fig_kpfcn(H,E)
S = guidata(H);
switch E.Key
case 'rightarrow'
set(S.ship,'XData',get(S.ship,'XData')+5);
case 'leftarrow'
set(S.ship,'XData',get(S.ship,'XData')-5);
case 'uparrow'
set(S.ship,'YData',get(S.ship,'YData')+5);
case 'downarrow'
set(S.ship,'YData',get(S.ship,'YData')-5);
end
end
end
Voss
Voss el 15 de Abr. de 2022
Editada: Voss el 15 de Abr. de 2022
There are different types of functions in MATLAB, including nested functions and subfunctions. In the code you shared just now, fig_kpfcn and circle are nested inside play_ISOL, for instance, which means they can access the variables in play_ISOL's workspace.
Now, I can't tell whether they're really nested in your version of the code or whether that's an artifact of how you've decided to copy and paste them here. Particularly in a GUI, in order for me to know how to help, it is necessary for me to know the structure of the whole code, which is why I asked to see the whole thing.
Personally, I like to use nested functions, so I'll make that assumption. In that case, you don't have to use guidata since the figure and other objects are accessible in all the functions, since they're all nested inside the main function. The code might look like this:
function isolation_game()
fig_clr = [0 0.6 0];
%the figure that holds the game.
S.fig = figure('units','pixels',... % Units of measurement
'name','ISOLATION',... % Name of Game
'menubar','none',... % No menu bar
'numbertitle','off',... % No number title (Figure 1, etc.)
'Resize','off',...
'position',[200 200 640 480],... % Position of game
'color',fig_clr,... % color of background
'keypressfcn',@fig_kpfcn,...% key pressed
'windowkeypressfcn',@fig_kpfcn,...% key pressed
'closereq',@fig_clsrqfcn,...% close the game
'busyaction','cancel',...
'renderer','opengl',...
'BackingStore','on',...
'windowbuttondownfcn',@fig_wbdfcn);
% theres some code that just makes buttons and makes axes invisible. Now
% I'm thinkin about it, it might be the axes code.
S.axs = axes('units','pix',...
...'position','default',...
'ycolor',fig_clr,...
'xcolor',fig_clr,...
'color',fig_clr,...
'xtick',[],'ytick',[],...
'xlim',[-.1 7.1],...
'ylim',[-.1 7.1],...
'visible','off');
S.pbtStart = uicontrol( ...
'Style','pushbutton', ...
'String','Start', ...
'Position',[500 45 100 50], ...
'Callback',@pbtStart_call);
S.pbtLDB = uicontrol( ...
'Style','pushbutton', ...
'String','LDB');
S.pbtLore = uicontrol( ...
'Style','pushbutton', ...
'String','Lore');
S.txt = uicontrol( ...
'Style','text', ...
'String','text');
xCenter = 3;
yCenter = 4;
radius = 1;
%ship = viscircles([xCenter, yCenter], radius, 'Color', 'c');
S.ship = circle(xCenter, yCenter, radius);
% set(gcf(), 'KeyPressFcn', @fig_kpfcn);
% guidata(S.ship,S);
%%the code i put in the question is code that happens when i press the
%%start button.
function [] = pbtStart_call(varargin)
% will also be used for pause and continue buttons (switch st8ment)
switch get(S.pbtStart,'string')
case 'Start'
set(S.pbtStart,'string','Pause',...
'position',[500 45 100 50],...
'fontsize',14); % Changle pushbutton label.
set(S.pbtLDB,'Visible','off','Enable','off');
set(S.pbtLore,'Visible','off','Enable','off');
set(S.txt,'Visible','off');
play_ISOL; % Initiate Gameplay.
end
end
function [] = play_ISOL()
S.currLVL = 1;
S.currSCR = 0;
end
function h = circle(xCenter,yCenter,radius)
hold on
th = 0:pi/50:2*pi;
xunit = radius * cos(th) + xCenter;
yunit = radius * sin(th) + yCenter;
h = plot(xunit, yunit, "Color", 'c', 'LineWidth', 2);
hold off
end
function [] = fig_kpfcn(~,E)
% S = guidata(H);
switch E.Key
case 'rightarrow'
set(S.ship,'XData',get(S.ship,'XData')+0.1);
case 'leftarrow'
set(S.ship,'XData',get(S.ship,'XData')-0.1);
case 'uparrow'
set(S.ship,'YData',get(S.ship,'YData')+0.1);
case 'downarrow'
set(S.ship,'YData',get(S.ship,'YData')-0.1);
end
end
function fig_clsrqfcn(~,~)
delete(S.fig);
end
function fig_wbdfcn(~,~)
end
end
I've changed the radius and center of the circle to make it consistent with the axes XLimits and YLimits, and I've removed 'Position','default' in the creation of the axes. These two things are why the circle didn't show up - the circle was outside the limits of the axes and the axes was too small.
The code above is self-contained (i.e., you can copy it into its own m-file and run it as-is) and it serves to create a circle that moves in response to key presses.
[If you want key presses to move the circle only when the game is in play (e.g., the start button has been clicked and it wasn't clicked again to pause the game, etc.), you can change when the figure's KeyPressFcn and WindowKeyPressFcn are set to fig_kpfcn, or you can have a variable that signifies whether the game is in play or paused/not started and use that variable in fig_kpfcn to selectively move the circle or ignore the key presses.]
something like this? i only put the code on sections where i think the variable goes.
j = 0; %game has yet to start
function [] = play_ISOL()
S.currLVL = 1;
S.currSCR = 0;
j = 1; %game has started
end
function [] = fig_kpfcn(~,E)
% S = guidata(H);
if j == 1
switch E.Key
case 'rightarrow'
set(S.ship,'XData',get(S.ship,'XData')+0.1);
case 'leftarrow'
set(S.ship,'XData',get(S.ship,'XData')-0.1);
case 'uparrow'
set(S.ship,'YData',get(S.ship,'YData')+0.1);
case 'downarrow'
set(S.ship,'YData',get(S.ship,'YData')-0.1);
end
end
end
Voss
Voss el 15 de Abr. de 2022
Yeah. (And also reset j to 0 if they click Pause, if the circle shouldn't move while the game is paused.)
NinaCodes
NinaCodes el 15 de Abr. de 2022
Thank you so much!! I've been trying to figure out why it wasn't moving for days now! I tweaked the code abit to (mostly position numbers), but my code is working now and circle moves! :D
Voss
Voss el 15 de Abr. de 2022
Excellent!

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Board games en Centro de ayuda y File Exchange.

Productos

Versión

R2021b

Preguntada:

el 15 de Abr. de 2022

Comentada:

el 15 de Abr. de 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by