Live mouse position on school-made game engine

84 Ansichten (letzte 30 Tage)
Noah
Noah am 31 Okt. 2022
Beantwortet: Suvansh Arora am 2 Nov. 2022
I'm making a pretty simple game of connect four and I'm looking for live feed of the mouses position on my game figure. The game itself works find and the game engine even comes with a built in function for getting mouse position on click, however I'm looking for passive mouse position, or the position without clicking. The classic solution to this problem calling the current point attribute of GCA, does not work for some reason. The function for getting the mouses global location does work but in the context of this assignment it really wouldn't make much sense and doesn't seem very reliable for something like this anyway.
At the end of the day, I am simply looking for a replacement, or fix, to get(gca, 'CurrentPoint') Attatched is my file and the game engine file.
get(gca, 'CurrentPoint');
My code
clear
clc
import('simpleGameEngine')
%% Initialize
%Import 16 Sprites from SpriteSheet (16 should be reserved for a blank space)
my_scene = simpleGameEngine('SpriteSheet.png',25,25,5,[255,255,255]);
%Establish a matrix used for background rendering
boardBackgroundRender = [16,16,16,16,16,16,16; 3,3,3,3,3,3,3; 3,3,3,3,3,3,3; 3,3,3,3,3,3,3; 3,3,3,3,3,3,3; 3,3,3,3,3,3,3; 3,3,3,3,3,3,3;];
drawScene(my_scene, boardBackgroundRender)
%Initialize board and other Essential Variables
stone = [];
mark = [];
height = zeros([1,7]);
moves = [];
solutions = [];
board = zeros([6,7]);
won = false;
player_2_auto = false;
%% Main Game Loop
while true
%Create Matrix for for sprite sheet positions
boardPlot = cat(1,[0,0,0,0,0,0,0],flip(board,1));
%Change all zeros in the board to 16 (Reserved blank space in spritesheet)
for idx = find(boardPlot == 0)
boardPlot(idx) = 16;
end
drawScene(my_scene, boardBackgroundRender, boardPlot)
%Get click data
[mouseRow,mouseCol,mouseBut] = getMouseInput(my_scene);
if (canplay(won, player_2_auto, height, mouseCol))
board(height(1,mouseCol)+1, mouseCol) = 1 + mod(length(moves), 2);
height(mouseCol) = 1 + height(mouseCol);
moves = [moves, mouseCol];
end
gamewon(board, height, moves)
mouseCol = 0;
end
%% Establish functions for playing
function canPlay = canplay(won, player_2_auto, height, col)
if(player_2_auto == true)
canPlay = false;
return
end
canPlay = ~won && (height(col) < 6);
return
end
function won = gamewon(board, height, moves)
x = moves(length(moves));
y = height(x);
if (y > 3 && (board(y - 1,x) == board(y,x)) && (board(y-2,x) == board(y,x)) && (board(y-3,x) == board(y,x)))
%mark_win(x, y, 0, -1);
won = true;
end
for dy = -1:1
nb = 0;
dx = 1;
while((x + dx <= 7) && (y + dx * dy <= 6) && y + dx * dy > 0)
if (board(y + dx * dy, x + dx) == board(y,x))
nb = nb + 1;
else
break;
end
dx = dx + 1;
end
dx= -1;
while((x + dx > 0) && (y + dx * dy <= 6) && (y + dx * dy > 0))
if (board(y + dx * dy, x + dx) == board(y,x))
nb = nb + 1;
else
break;
end
dx = dx - 1;
end
if (nb >= 3)
won = true;
end
end
end
simpleGameEngine.m
% The Simple Game Engine is a class from object-oriented programming.
% If you are unfamiliar with object oriented programming, here is a quick
% crash course:
%
% Classes are a higher level of organizing programs beyond functions, they
% group together the functions (called methods) and variables (properties)
% of whatever it is you are trying to do. When you make a variable (called
% an object) from a class, it has all the properties from that class
% bundled together. This mimics how we naturally categorize things in real
% life. For example, cats are a class of animals, methods are the things a
% cat can do (e.g. pounce, meow, etc), properties describe a cat (e.g.
% color, age, location, etc), and objects are individual cats (where each
% of the properties has a set value).
%
% The one extra bit of syntax you need to understand what's going on below
% is how to access properties of an object:
% Property "prop" of object "obj" is "obj.prop"
% The simpleGameEngine class inherets from the handle class because we
% want the game objects to be updated by their methods, specifically
% my_figure and my_image
classdef simpleGameEngine < handle
properties
sprites = {}; % color data of the sprites
sprites_transparency = {}; % transparency data of the sprites
sprite_width = 0;
sprite_height = 0;
background_color = [0, 0, 0];
zoom = 1;
my_figure; % figure identifier
my_image; % image data
end
methods
function obj = simpleGameEngine(sprites_fname, sprite_height, sprite_width, zoom, background_color)
% simpleGameEngine
% Input:
% 1. File name of sprite sheet as a character array
% 2. Height of the sprites in pixels
% 3. Width of the sprites in pixels
% 4. (Optional) Zoom factor to multiply image by in final figure (Default: 1)
% 5. (Optional) Background color in RGB format as a 3 element vector (Default: [0,0,0] i.e. black)
% Output: an SGE scene variable
% Note: In RGB format, colors are specified as a mixture of red, green, and blue on a scale of 0 to 255. [0,0,0] is black, [255,255,255] is white, [255,0,0] is red, etc.
% Example:
% my_scene = simpleGameEngine('tictactoe.png',16,16,5,[0,150,0]);
% load the input data into the object
obj.sprite_width = sprite_width;
obj.sprite_height = sprite_height;
if nargin > 4
obj.background_color = background_color;
end
if nargin > 3
obj.zoom = zoom;
end
% read the sprites image data and transparency
[sprites_image, ~, transparency] = imread(sprites_fname);
% determine how many sprites there are based on the sprite size
% and image size
sprites_size = size(sprites_image);
sprite_row_max = (sprites_size(1)+1)/(sprite_height+1);
sprite_col_max = (sprites_size(2)+1)/(sprite_width+1);
% Make a transparency layer if there is none (this happens when
% there are no transparent pixels in the file).
if isempty(transparency)
transparency = 255*ones(sprites_size,'uint8');
else
% If there is a transparency layer, use repmat() to
% replicate is to all three color channels
transparency = repmat(transparency,1,1,3);
end
% loop over the image and load the individual sprite data into
% the object
for r=1:sprite_row_max
for c=1:sprite_col_max
r_min = sprite_height*(r-1)+r;
r_max = sprite_height*r+r-1;
c_min = sprite_width*(c-1)+c;
c_max = sprite_width*c+c-1;
obj.sprites{end+1} = sprites_image(r_min:r_max,c_min:c_max,:);
obj.sprites_transparency{end+1} = transparency(r_min:r_max,c_min:c_max,:);
end
end
end
function drawScene(obj, background_sprites, foreground_sprites)
% draw_scene
% Input:
% 1. an SGE scene, which gains focus
% 2. A matrix of sprite IDs, the arrangement of the sprites in the figure will be the same as in this matrix
% 3. (Optional) A second matrix of sprite IDs of the same size as the first. These sprites will be layered on top of the first set.
% Output: None
% Example: The following will create a figure with 3 rows and 3 columns of sprites
% drawScene(my_scene, [4,5,6;7,8,9;10,11,12], [1,1,1;1,2,1;1,1,1]);
scene_size = size(background_sprites);
% Error checking: make sure the bg and fg are the same size
if nargin > 2
if ~isequal(scene_size, size(foreground_sprites))
error('Background and foreground matrices of scene must be the same size.')
end
end
num_rows = scene_size(1);
num_cols = scene_size(2);
% initialize the scene_data array to the correct size and type
scene_data = zeros(obj.sprite_height*num_rows, obj.sprite_width*num_cols, 3, 'uint8');
% loop over the rows and colums of the tiles in the scene to
% draw the sprites in the correct locations
for tile_row=1:num_rows
for tile_col=1:num_cols
% Save the id of the current sprite(s) to make things
% easier to read later
bg_sprite_id = background_sprites(tile_row,tile_col);
if nargin > 2
fg_sprite_id = foreground_sprites(tile_row,tile_col);
end
% Build the tile layer by layer, starting with the
% background color
tile_data = zeros(obj.sprite_height,obj.sprite_width,3,'uint8');
for rgb_idx = 1:3
tile_data(:,:,rgb_idx) = obj.background_color(rgb_idx);
end
% Layer on the first sprite. Note that the tranparency
% data also ranges from 0 (transparent) to 255
% (visible)
tile_data = obj.sprites{bg_sprite_id} .* (obj.sprites_transparency{bg_sprite_id}/255) + ...
tile_data .* ((255-obj.sprites_transparency{bg_sprite_id})/255);
% If needed, layer on the second sprite
if nargin > 2
tile_data = obj.sprites{fg_sprite_id} .* (obj.sprites_transparency{fg_sprite_id}/255) + ...
tile_data .* ((255-obj.sprites_transparency{fg_sprite_id})/255);
end
% Calculate the pixel location of the top-left corner
% of the tile
rmin = obj.sprite_height*(tile_row-1);
cmin = obj.sprite_width*(tile_col-1);
% Write the tile to the scene_data array
scene_data(rmin+1:rmin+obj.sprite_height,cmin+1:cmin+obj.sprite_width,:)=tile_data;
end
end
% handle zooming
big_scene_data = imresize(scene_data,obj.zoom,'nearest');
% This part is a bit tricky, but avoids some latency, the idea
% is that we only want to completely create a new figure if we
% absolutely have to: the first time the figure is created,
% when the old figure has been closed, or if the scene is
% resized. Otherwise, we just update the image data in the
% current image, which is much faster.
if isempty(obj.my_figure) || ~isvalid(obj.my_figure)
% inititalize figure
obj.my_figure = figure();
% set guidata to the key press and release functions,
% this allows keeping track of what key has been pressed
obj.my_figure.KeyPressFcn = @(src,event)guidata(src,event.Key);
obj.my_figure.KeyReleaseFcn = @(src,event)guidata(src,0);
% actually display the image to the figure
obj.my_image = imshow(big_scene_data,'InitialMagnification', 100);
elseif isempty(obj.my_image) || ~isprop(obj.my_image, 'CData') || ~isequal(size(big_scene_data), size(obj.my_image.CData))
% Re-display the image if its size changed
figure(obj.my_figure);
obj.my_image = imshow(big_scene_data,'InitialMagnification', 100);
else
% otherwise just update the image data
obj.my_image.CData = big_scene_data;
end
end
function key = getKeyboardInput(obj)
% getKeyboardInput
% Input: an SGE scene, which gains focus
% Output: next key pressed while scene has focus
% Note: the operation of the program pauses while it waits for input
% Example:
% k = getKeyboardInput(my_scene);
% Bring this scene to focus
figure(obj.my_figure);
% Pause the program until the user hits a key on the keyboard,
% then return the key pressed. The loop is required so that
% we don't exit on a mouse click instead.
keydown = 0;
while ~keydown
keydown = waitforbuttonpress;
end
key = get(obj.my_figure,'CurrentKey');
end
function [row,col,button] = getMouseInput(obj)
% getMouseInput
% Input: an SGE scene, which gains focus
% Output:
% 1. The row of the tile clicked by the user
% 2. The column of the tile clicked by the user
% 3. (Optional) the button of the mouse used to click (1,2, or 3 for left, middle, and right, respectively)
%
% Notes: A set of “crosshairs” appear in the scene’s figure,
% and the program will pause until the user clicks on the
% figure. It is possible to click outside the area of the
% scene, in which case, the closest row and/or column is
% returned.
%
% Example:
% [row,col,button] = getMouseInput (my_scene);
% Bring this scene to focus
figure(obj.my_figure);
% Get the user mouse input
[X,Y,button] = ginput(1);
% Convert this into the tile row/column
row = ceil(Y/obj.sprite_height/obj.zoom);
col = ceil(X/obj.sprite_width/obj.zoom);
% Calculate the maximum possible row and column from the
% dimensions of the current scene
sceneSize = size(obj.my_image.CData);
max_row = sceneSize(1)/obj.sprite_height/obj.zoom;
max_col = sceneSize(2)/obj.sprite_width/obj.zoom;
% If the user clicked outside the scene, return instead the
% closest row and/or column
if row < 1
row = 1;
elseif row > max_row
row = max_row;
end
if col < 1
col = 1;
elseif col > max_col
col = max_col;
end
end
function [X,Y] = getMousePos(obj)
% getMouseInput
% Input: an SGE scene, which gains focus
% Output:
% 1. The row of the tile clicked by the user
% 2. The column of the tile clicked by the user
% 3. (Optional) the button of the mouse used to click (1,2, or 3 for left, middle, and right, respectively)
%
% Notes: A set of “crosshairs” appear in the scene’s figure,
% and the program will pause until the user clicks on the
% figure. It is possible to click outside the area of the
% scene, in which case, the closest row and/or column is
% returned.
%
% Example:
% [row,col,button] = getMouseInput (my_scene);
% Bring this scene to focus
figure(obj.my_figure);
C = get (gca, 'CurrentPoint');
% Get the user mouse input
X = C(1);
Y = C(2);
end
end
end

Antworten (1)

Suvansh Arora
Suvansh Arora am 2 Nov. 2022
I have tried creating an application that updates the current mouse position in the title itself, I hope this will help.
gcf = figure
plot(1:10)
set (gcf, 'WindowButtonMotionFcn', @mouseMove);
function mouseMove (object, eventdata)
C = get (gca, 'CurrentPoint');
title(gca, ['(X,Y) = (', num2str(C(1,1)), ', ',num2str(C(1,2)), ')']);
end
In order to find more information about the approach and function used, please follow the links below

Tags

Produkte


Version

R2022b

Community Treasure Hunt

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

Start Hunting!

Translated by