300 lines
13 KiB
Matlab
300 lines
13 KiB
Matlab
% Original author: En Yi
|
|
% The card container class used in the solitaire game
|
|
% Not optimised though
|
|
% Anyone can modify it, just need to give credits to the original author
|
|
classdef cardHolder < handle
|
|
%% Deck Properties
|
|
properties (SetAccess = private)
|
|
%Deck position
|
|
x % x position of the top left of the holder
|
|
y % y position of the top left of the holder
|
|
% Card dimension and offset
|
|
card_width
|
|
card_height
|
|
offset % The offset between display each card in a deck
|
|
cards % The cards is currently holding
|
|
% Card deck orientation and dimensions
|
|
deck_orientation % Either display horizontal or vertical
|
|
start_display_index % Display only a number of cards in a deck, -1 for display all
|
|
current_display_index % Current number of cards to be displayed
|
|
% Overall deck dimension, used for collision purposes
|
|
deck_width
|
|
deck_height
|
|
% Deck properties
|
|
always_hidden % Never open the hidden cards
|
|
receivable
|
|
% Deck graphics handle, used for updating the deck's graphics
|
|
card_graphics_data = {}
|
|
card_draw_handle = []
|
|
card_text = []
|
|
end
|
|
properties (SetAccess = public)
|
|
selected_start_index % The card index which is selected
|
|
hidden_start_index % The number of cards that is hidden
|
|
end
|
|
methods
|
|
%% Constructor
|
|
function cH = cardHolder(x,y,cards,card_width,card_height,offset,deck_orientation,start_display_index,hidden_cards,always_hidden,receivable)
|
|
cH.x = x;
|
|
cH.y = y;
|
|
|
|
cH.deck_orientation = deck_orientation;
|
|
if start_display_index<1
|
|
start_display_index = -1;
|
|
end
|
|
cH.start_display_index = start_display_index;
|
|
cH.current_display_index = start_display_index;
|
|
|
|
cH.cards = cards;
|
|
cH.card_width = card_width;
|
|
cH.card_height = card_height;
|
|
cH.offset = offset;
|
|
|
|
cH.receivable = receivable ;
|
|
cH.always_hidden = always_hidden;
|
|
hidden_cards = min(hidden_cards,length(cards));
|
|
cH.hidden_start_index = hidden_cards;
|
|
|
|
cH.selected_start_index = 0;
|
|
cH.update_deck_dimensions()
|
|
end
|
|
%% Deck Get Functions
|
|
% Get the number of cards in the deck
|
|
function n_of_cards = get_Number_Of_Cards(cH)
|
|
n_of_cards = length(cH.cards);
|
|
end
|
|
function receive = is_Receivable(cH)
|
|
receive = cH.receivable;
|
|
end
|
|
% Get the card at the bottom of the selected cards
|
|
function card = get_bottom_selected(cH)
|
|
card = cH.cards(end-cH.selected_start_index+1);
|
|
end
|
|
|
|
% Get the last card, which is top of the deck
|
|
function lastcard = get_Last_Cards(cH)
|
|
% If empty, return 0
|
|
if cH.is_Empty()
|
|
lastcard = 0;
|
|
return
|
|
end
|
|
|
|
if (cH.get_Number_Of_Cards()-cH.hidden_start_index)>0
|
|
lastcard = cH.cards(end); % Return the card number if not hidden
|
|
else
|
|
lastcard = -1; % If hidden, return -1;
|
|
end
|
|
end
|
|
%% Deck Check Functions
|
|
%Check if the deck is empty
|
|
function empty = is_Empty(cH)
|
|
empty = (cH.get_Number_Of_Cards() == 0);
|
|
end
|
|
|
|
%Check if there is a collision with a deck
|
|
function collide = check_Deck_Collision(cH,x,y,type)
|
|
|
|
if strcmp(type,'full') %Check for entire deck collision
|
|
xrange = [cH.x cH.x+cH.deck_width];
|
|
yrange = [cH.y-cH.deck_height cH.y];
|
|
elseif strcmp(type,'first') %Check for only first card collision
|
|
xoffset = cH.deck_width - cH.card_width;
|
|
yoffset = cH.deck_height - cH.card_height;
|
|
xrange = [cH.x+xoffset cH.x+cH.deck_width];
|
|
yrange = [cH.y-cH.deck_height cH.y-yoffset];
|
|
end
|
|
|
|
collide = (x>xrange(1) && x<xrange(2)&& y>yrange(1) && y<yrange(2));
|
|
end
|
|
|
|
%Check the selected card index
|
|
function sel_num = check_selection(cH,sel_x,sel_y)
|
|
% If the deck is empty, don't proceed to calculations
|
|
if cH.is_Empty()
|
|
sel_num = 0;
|
|
return
|
|
end
|
|
% Set up for the calculation depending on orientation
|
|
if strcmp(cH.deck_orientation,'vertical')
|
|
sel_point = sel_y;
|
|
ref_point = cH.y-cH.deck_height;
|
|
first_card_range = cH.card_height;
|
|
elseif strcmp(cH.deck_orientation,'horizontal')
|
|
sel_point = sel_x;
|
|
ref_point = cH.x+cH.deck_width;
|
|
first_card_range = cH.card_width;
|
|
end
|
|
% Check which card is selected
|
|
relative_sel_point = abs(sel_point-ref_point);
|
|
if relative_sel_point<=first_card_range
|
|
sel_num = 1;
|
|
else
|
|
sel_num = 1+ceil((relative_sel_point - first_card_range)/cH.offset);
|
|
end
|
|
% Check if the selected card is hidden
|
|
if sel_num>cH.get_Number_Of_Cards()-cH.hidden_start_index
|
|
sel_num = -1;
|
|
end
|
|
end
|
|
%% Deck Modifying Functions
|
|
% Add cards to the end, which is the top of the deck
|
|
function append_Cards(cH,new_cards)
|
|
cH.cards = [cH.cards new_cards];
|
|
if cH.start_display_index>=0
|
|
% Increase the current number of cards to display
|
|
cH.current_display_index = cH.current_display_index+length(new_cards);
|
|
% This is to limit how many cards can be display at a time,may make it conditional
|
|
cH.current_display_index = min(cH.current_display_index,cH.start_display_index);
|
|
end
|
|
cH.update_deck_dimensions(); %Update the deck dimensions
|
|
end
|
|
|
|
% Remove the selected cards
|
|
function remove_Selected_Cards(cH)
|
|
cH.cards = cH.cards(1:end-cH.selected_start_index);
|
|
|
|
if cH.current_display_index>0
|
|
% Decrease the current number of cards to display
|
|
cH.current_display_index = cH.current_display_index-cH.selected_start_index;
|
|
cH.current_display_index = max(cH.current_display_index,1);
|
|
end
|
|
%fprintf('Current display index: %d\n',cH.current_display_index)
|
|
%cH.current_display_index = min(cH.current_display_index,cH.start_display_index);
|
|
|
|
%cH.selected_start_index = 0;
|
|
cH.update_deck_dimensions()
|
|
end
|
|
|
|
% Reveal a specified number of hidden cards from the top
|
|
function reveal_Hidden_Card(cH,amount)
|
|
cH.hidden_start_index = cH.hidden_start_index - amount;
|
|
end
|
|
|
|
% Transfer selected cards to another deck
|
|
function transfer_Selected_Cards(cH,cH_to,varargin)
|
|
selected_cards = cH.cards(end-cH.selected_start_index+1:end);
|
|
if ~isempty(varargin)
|
|
selected_cards = fliplr(selected_cards);
|
|
end
|
|
cH_to.append_Cards(selected_cards);
|
|
cH.remove_Selected_Cards();
|
|
end
|
|
|
|
% Reset the number of cards to display
|
|
function set_Current_Display(cH,num)
|
|
if num<0
|
|
cH.current_display_index = cH.start_display_index;
|
|
else
|
|
cH.current_display_index = max(num,1);
|
|
end
|
|
cH.update_deck_dimensions()
|
|
end
|
|
%% Deck Update/Reset Functions
|
|
% Update the deck dimensions. MUST be called when cards are altered
|
|
function update_deck_dimensions(cH)
|
|
% Check how many are being display
|
|
if cH.start_display_index>0
|
|
cards_to_display = min(cH.current_display_index,cH.get_Number_Of_Cards());
|
|
else
|
|
cards_to_display = cH.get_Number_Of_Cards();
|
|
end
|
|
%If there is cards to display
|
|
if cards_to_display>0
|
|
if strcmp(cH.deck_orientation,'vertical')
|
|
cH.deck_width = cH.card_width;
|
|
cH.deck_height = cH.card_height+cH.offset*(cards_to_display-1);
|
|
elseif strcmp(cH.deck_orientation,'horizontal')
|
|
cH.deck_width = cH.card_width+cH.offset*(cards_to_display-1);
|
|
cH.deck_height = cH.card_height;
|
|
end
|
|
else
|
|
cH.deck_width = cH.card_width;
|
|
cH.deck_height = cH.card_height;
|
|
end
|
|
end
|
|
function update_Deck_Graphics(cH,disp_axes)
|
|
cH.wipe_Deck_Graphics();
|
|
cH.render_Deck(disp_axes);
|
|
end
|
|
|
|
% Clear the cards in the deck
|
|
function clear_Deck(cH)
|
|
cH.cards = [];
|
|
end
|
|
%% Deck Console Functions
|
|
% Display the cards on console
|
|
function display_Cards(cH)
|
|
disp(cH.cards)
|
|
end
|
|
|
|
%% Rendering functions
|
|
% Render the deck outline
|
|
function render_deck_outline(cH,disp_axes)
|
|
line(disp_axes,[cH.x cH.x+cH.card_width cH.x+cH.card_width cH.x cH.x],...
|
|
[cH.y cH.y cH.y-cH.card_height cH.y-cH.card_height cH.y],...
|
|
'PickablePart','none','Color',[1 1 1],'LineWidth',1)
|
|
end
|
|
|
|
% Render the cards in the deck
|
|
function render_Deck(cH,disp_axes)
|
|
% Draw shadow
|
|
% if cH.get_Number_Of_Cards()>0
|
|
% deck_vertices(1,:) = [cH.x cH.x+cH.deck_width cH.x+cH.deck_width cH.x]+5;
|
|
% deck_vertices(2,:) = [cH.y cH.y cH.y-cH.deck_height cH.y-cH.deck_height]+5;
|
|
% cH.card_draw_handle(1) = patch(deck_vertices(1,:),deck_vertices(2,:),[1 0 0],'Parent',disp_axes,'PickableParts','none');
|
|
% end
|
|
if cH.current_display_index>0
|
|
start_card = cH.get_Number_Of_Cards()-cH.current_display_index+1;
|
|
start_card = max(start_card,1);
|
|
else
|
|
start_card = 1;
|
|
end
|
|
for i = start_card:cH.get_Number_Of_Cards()
|
|
if strcmp(cH.deck_orientation,'vertical')
|
|
botleft_x = cH.x+0.5;
|
|
botright_y = cH.y-cH.card_height -cH.offset*(i-start_card)+0.5;
|
|
|
|
% text_pos = [cH.x cH.y-cH.offset*(i-start_card)-0.5];
|
|
elseif strcmp(cH.deck_orientation,'horizontal')
|
|
botleft_x = cH.x +cH.offset*(i-start_card)+0.5;
|
|
botright_y = cH.y-cH.card_height+0.5;
|
|
% text_pos = [cH.x+cH.offset*(i-start_card) cH.y-0.5];
|
|
end
|
|
|
|
|
|
% The selection starts from the top of the stack
|
|
if (i<=cH.hidden_start_index || cH.always_hidden)
|
|
%set(cH.card_draw_handle(i),'AlphaData',0.5);
|
|
img = cH.cards(i).get_Card_Image('back');
|
|
else
|
|
img = cH.cards(i).get_Card_Image('front');
|
|
end
|
|
if i > length(cH.cards)- cH.selected_start_index
|
|
dark = ones(size(img))*0.2;
|
|
img = img - dark;
|
|
end
|
|
|
|
cH.card_draw_handle(i+1) = image(disp_axes,botleft_x,botright_y,...
|
|
img,'PickablePart','none');
|
|
% if i > length(cH.cards)- cH.selected_start_index
|
|
% set(cH.card_draw_handle(i),'AlphaData',0.5);
|
|
% end
|
|
|
|
% cH.card_text(i) = text(disp_axes,text_pos(1),text_pos(2),num2str(cH.cards(i)),'PickableParts','none');
|
|
end
|
|
end
|
|
|
|
% Delete the display cards in the deck, used for updating the deck
|
|
function wipe_Deck_Graphics(cH)
|
|
if ~isempty(cH.card_draw_handle)
|
|
delete(cH.card_draw_handle)
|
|
cH.card_draw_handle = [];
|
|
end
|
|
if ~isempty(cH.card_text)
|
|
delete(cH.card_text)
|
|
cH.card_text = [];
|
|
end
|
|
end
|
|
|
|
end
|
|
end |