📄 carddraw.pas
字号:
{
接龙游戏的牌局图像处理
牌索引 0..12 黑桃(A,2..K) 13..25 红桃(A,2..K) 26..38 梅花(A,2..K) 39..51 方块(A,2..K)
牌图像索引 0-51[A(草花、方块、红桃、黑桃),2,…,K];53-65牌背面
黄文林 2006-02-11
}
unit CardDraw;
interface
uses
Windows, Classes, Forms, Controls, Graphics, ExtCtrls, MMSystem, CardLib, Cards, untScore;
type
TCardDraw = class
private
FCards: TCards;
FDesk, FCurrentDesk: TImage; //桌面操作Image控件(FDesk 临时, FCurrentDesk显示)
FCardWidth, FCardHeight: Integer; //扑克牌的大小
FCardBackIndex: Integer; //扑克牌背面图像索引值
FPlayerCardRect, FPlayerCoverCardRect: array[0..PLAYER_COUNT - 1] of TRect; //玩家牌,盖牌区域
FOutCardRect: array[0..3] of TRect; //各花色出牌区域
FComputerSound: Boolean; //电脑玩家声音开关
FHumanSound: Boolean; //玩家出牌声音开关
FSpeed: Integer; //游戏动画速度 -1 - 快 0 - 中(默认) 1 - 慢
FPlayerName: array[0..3] of String; //玩家姓名
FTestMode: Boolean; //测试模式, 为真时可显示所有玩家的牌
procedure InitRect; //初始化牌区域
procedure InitDesk; //初始化桌面
procedure StartGame; //开始游戏
procedure EndGame; //结束游戏
procedure GameGo; //游戏进行
procedure ComputerGo; //电脑走
procedure ShowScore; //显示分数
procedure Lock; //锁定用户操作
procedure UnLock; //开启用户操作
procedure DrawPlayerName(APlayerIndex: Integer); //画玩家名字
procedure ErasePlayerName(APlayerIndex: Integer); //擦玩家名字
procedure DrawPlayerCard(APlayerIndex: Integer); //画各玩家牌
procedure DrawPlayerCoverCardRect(APlayerIndex: Integer); //画各玩家盖牌区(重叠,反面)
procedure DrawPlayerCoverCard(APlayerIndex: Integer); //画各玩家盖的牌(平铺,正面)
procedure DrawMyCoverCard; //画当前玩家已盖牌
procedure DrawNotOutCard(ACardIndex: Integer); //画玩家点击的不能出的牌
procedure DrawOutCard(ACardSuit: Integer); //画已出的牌
procedure DrawDesk; //画桌面所有
procedure UpdateDesk; //更新显示桌面
procedure PlayerCardClick(ACardIndex: Integer); //当前玩家牌区点击
procedure PlayerCoverCardClick; //当前玩家盖牌区点击
procedure PlayCardSound(AGoState: TGoCardState); //播放声音
procedure MoveCard(ACardID: Integer; AStart, AEnd: TPoint; AMode: Integer); //移动扑克
procedure MovieCard(AGoCard: TGoCard); //牌动画
procedure MovieOutCard(AGoCard: TGoCard); //出牌动画
procedure MovieCoverCard(AGoCard: TGoCard); //盖牌动画
procedure SetCardBackIndex(ACardIndex: Integer); //设置牌背景图片
function GetOutCardPoint(ACardSuit, ACardNum: Integer): TPoint; //得到已出牌的左上位置
function GetPlayerCardPoint(APlayerIndex, ACardIndex: Integer): TPoint; //得到玩家指定牌的左上位置
function GetPlayerNamePoint(APlayerIndex: Integer): TPoint; //得到玩家名字的左上位置
function CardIDToPicID(ACardIndex: Integer): Integer; //牌索引转图片索引
function InRect(ARect: TRect; APoint: TPoint): Boolean; //点是否在区域中
public
property CardBackIndex: Integer read FCardBackIndex write SetCardBackIndex;
property ComputerSound: Boolean read FComputerSound write FComputerSound;
property HumanSound: Boolean read FHumanSound write FHumanSound;
property Speed: Integer read FSpeed write FSpeed;
property TestMode: Boolean read FTestMode write FTestMode;
constructor Create(ADesk: TImage);
destructor Destory;
procedure NewGame; //新游戏 (开局, 重新计分)
procedure MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure SetPlayerName(APlayerIndex: Integer; AName: string); //设置玩家姓名
function GetPlayerName(APlayerIndex: Integer): String; //画玩家姓名
end;
implementation
{$R sound.res}
const
CARD_BETWEEN_SPACE = 15;
CARD_BORDER_SPACE = 10;
constructor TCardDraw.Create(ADesk: TImage);
begin
cdtInit(FCardWidth, FCardHeight);
FCards := TCards.Create;
FCurrentDesk := ADesk;
FDesk := TImage.Create(nil);
FDesk.Width := FCurrentDesk.Width;
FDesk.Height := FCurrentDesk.Height;
FCardBackIndex := 54;
InitRect;
InitDesk;
FCurrentDesk.Canvas.CopyRect(FCurrentDesk.ClientRect, FDesk.Canvas, FDesk.ClientRect);
end;
destructor TCardDraw.Destory;
begin
FDesk.Free;
FCards.Free;
cdtTerm;
end;
procedure TCardDraw.InitDesk;
begin
FDesk.Canvas.Pen.Color := clGreen;
FDesk.Canvas.Brush.Color := clGreen;
FDesk.Canvas.Rectangle(0, 0, FCurrentDesk.Width,FCurrentDesk.Height);
end;
procedure TCardDraw.InitRect;
var
hs: Integer;
begin
//各玩家画牌区域
FPlayerCardRect[0].Left := (FDesk.Width - (PLAYER_CARD_COUNT - 1) * CARD_BETWEEN_SPACE - FCardWidth) div 2;
FPlayerCardRect[0].Right := FPlayerCardRect[0].Left + 12 * CARD_BETWEEN_SPACE + FCardWidth;
FPlayerCardRect[0].Top := FDesk.Height - FCardHeight - CARD_BORDER_SPACE;
FPlayerCardRect[0].Bottom := FPlayerCardRect[0].Top + FCardHeight;
FPlayerCardRect[1].Left := FDesk.Width - FCardWidth - CARD_BORDER_SPACE;
FPlayerCardRect[1].Right := FPlayerCardRect[1].Left + FCardWidth;
FPlayerCardRect[1].Top := (FDesk.Height - (PLAYER_CARD_COUNT - 1) * CARD_BETWEEN_SPACE - FCardHeight) div 2;
FPlayerCardRect[1].Bottom := FPlayerCardRect[1].Top + 12 * CARD_BETWEEN_SPACE + FCardHeight;
FPlayerCardRect[2].Left := FPlayerCardRect[0].Left;
FPlayerCardRect[2].Right := FPlayerCardRect[2].Left + 12 * CARD_BETWEEN_SPACE + FCardWidth;
FPlayerCardRect[2].Top := CARD_BORDER_SPACE;
FPlayerCardRect[2].Bottom := FPlayerCardRect[2].Top + FCardHeight;
FPlayerCardRect[3].Left := CARD_BORDER_SPACE;
FPlayerCardRect[3].Right := FPlayerCardRect[3].Left + FCardWidth;
FPlayerCardRect[3].Top := FPlayerCardRect[1].Top;
FPlayerCardRect[3].Bottom := FPlayerCardRect[3].Top + 12 * CARD_BETWEEN_SPACE + FCardHeight;
//各玩家盖牌区域
FPlayerCoverCardRect[0].Left := FPlayerCardRect[0].Left - (FCardWidth + CARD_BORDER_SPACE);
FPlayerCoverCardRect[0].Right := FPlayerCoverCardRect[0].Left + FCardWidth;
FPlayerCoverCardRect[0].Top := FPlayerCardRect[0].Top;
FPlayerCoverCardRect[0].Bottom := FPlayerCoverCardRect[0].Top + FCardHeight;
FPlayerCoverCardRect[1].Left := FPlayerCardRect[1].Left;
FPlayerCoverCardRect[1].Right := FPlayerCoverCardRect[1].Left + FCardWidth;
FPlayerCoverCardRect[1].Top := FPlayerCardRect[0].Top;
FPlayerCoverCardRect[1].Bottom := FPlayerCoverCardRect[1].Top + FCardHeight;
FPlayerCoverCardRect[2].Left := FPlayerCardRect[2].Right + CARD_BORDER_SPACE;
FPlayerCoverCardRect[2].Right := FPlayerCoverCardRect[2].Left + FCardWidth;
FPlayerCoverCardRect[2].Top := FPlayerCardRect[2].Top;
FPlayerCoverCardRect[2].Bottom := FPlayerCoverCardRect[2].Top + FCardHeight;
FPlayerCoverCardRect[3].Left := FPlayerCardRect[3].Left;
FPlayerCoverCardRect[3].Right := FPlayerCoverCardRect[3].Left + FCardWidth;
FPlayerCoverCardRect[3].Top := FPlayerCardRect[2].Top;
FPlayerCoverCardRect[3].Bottom := FPlayerCoverCardRect[3].Top + FCardHeight;
//已出牌画牌区域
for hs := 0 to 3 do
begin
FOutCardRect[hs].Left := (FDesk.Width - FCardWidth * 4 - CARD_BETWEEN_SPACE * 3) div 2 + (FCardWidth + CARD_BETWEEN_SPACE) * hs;
FOutCardRect[hs].Right := FOutCardRect[hs].Left + FCardWidth;
FOutCardRect[hs].Top := FPlayerCardRect[1].Top;
FOutCardRect[hs].Bottom := FPlayerCardRect[1].Bottom;
end;
end;
function TCardDraw.CardIDToPicID(ACardIndex: Integer): Integer;
var
m, n: Integer;
begin
if ACardIndex = scNone then //如果索引为空值,则返回空。
begin
Result := scNone;
Exit;
end;
m := ACardIndex div 13;
n := ACardIndex mod 13;
case m of
0: m := 3;
1: m := 2;
2: m := 0;
3: m := 1;
end;
Result := n * 4 + m;
end;
function TCardDraw.GetPlayerCardPoint(APlayerIndex, ACardIndex: Integer): TPoint;
begin
case APlayerIndex of
0:
begin
Result.X := FPlayerCardRect[APlayerIndex].Left + ACardIndex * CARD_BETWEEN_SPACE;
Result.Y := FPlayerCardRect[APlayerIndex].Top;
end;
1:
begin
Result.X := FPlayerCardRect[APlayerIndex].Left;
Result.Y := FPlayerCardRect[APlayerIndex].Top + (PLAYER_CARD_COUNT - ACardIndex - 1)* CARD_BETWEEN_SPACE;
end;
2:
begin
Result.X := FPlayerCardRect[APlayerIndex].Left + (PLAYER_CARD_COUNT - ACardIndex - 1)* CARD_BETWEEN_SPACE;
Result.Y := FPlayerCardRect[APlayerIndex].Top;
end;
3:
begin
Result.X := FPlayerCardRect[APlayerIndex].Left;
Result.Y := FPlayerCardRect[APlayerIndex].Top + ACardIndex * CARD_BETWEEN_SPACE;
end;
end;
end;
procedure TCardDraw.NewGame;
begin
FCards.NewGame;
StartGame;
end;
procedure TCardDraw.StartGame;
var
i: Integer;
begin
FCards.StartGame;
InitDesk;
for i := 0 to 3 do
DrawPlayerName(i);
DrawDesk;
if FCards.CurrentPlayer <> 0 then
GameGo;
UnLock;
end;
procedure TCardDraw.EndGame;
var
i: Integer;
begin
Lock;
//显示各玩家的盖牌
for i := 0 to PLAYER_COUNT - 1 do
DrawPlayerCoverCard(i);
UpdateDesk;
//打开分数统计窗
ShowScore;
if frmScore.Num = 0 then //如果一局,则开局
NewGame
else
StartGame;
end;
procedure TCardDraw.GameGo;
begin
if FCards.State = gsEnd then
begin
EndGame;
exit;
end;
while FCards.CurrentPlayer <> 0 do //当玩家不为当前玩家时,则电脑出牌
ComputerGo;
end;
procedure TCardDraw.ComputerGo;
var
goCard: TGoCard;
begin
gocard := FCards.ComputerGo;
if FComputerSound then //播放出牌声音
PlayCardSound(gocard.State);
MovieCard(gocard);
if FCards.State = gsEnd then
begin
EndGame;
exit;
end;
end;
procedure TCardDraw.MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
pt: TPoint;
rt: TRect;
i, j: Integer;
begin
if FCards.State = gsEnd then Exit; //如果游戏结束,则退出.
Lock;
pt.X := X;
pt.Y := Y;
//如果点击盖牌区,且盖牌区有盖牌时,打开盖牌列表
if InRect(FPlayerCoverCardRect[0], pt) and (FCards.PlayerCoverCards[0].Count > 0) then
begin
PlayerCoverCardClick;
FCurrentDesk.OnMouseUp := MouseUp;
end
//测试模式时,电脑帮当前玩家出牌
else if FTestMode then
begin
repeat
ComputerGo;
until FCards.CurrentPlayer = 0;
UnLock;
exit;
end;
//如果点击玩家牌区
if InRect(FPlayerCardRect[0], pt) then
begin
j := -1;
for i := 0 to 12 do
begin
rt.Left := FPlayerCardRect[0].Left + CARD_BETWEEN_SPACE * i;
rt.Right := rt.Left + FCardWidth;
rt.Top := FPlayerCardRect[0].Top;
rt.Bottom := rt.Top + FCardHeight;
if (FCards.PlayerCards[0].Card[i] <> scNone) and InRect(rt, pt) then
j := i;
end;
//如果点击的位置有牌对应
if j >= 0 then
PlayerCardClick(j);
end;
UnLock;
end;
procedure TCardDraw.MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
//当打开盖牌区时,还原盖牌区
InitDesk;
DrawDesk;
FCurrentDesk.OnMouseUp := nil;
end;
function TCardDraw.InRect(ARect: TRect; APoint: TPoint): Boolean;
begin
Result := (APoint.X >= ARect.Left) and (APoint.X <= ARect.Right)
and (APoint.Y >= ARect.Top) and (APoint.Y <= ARect.Bottom);
end;
procedure TCardDraw.ShowScore;
begin
//打开分数窗口
frmScore.SetScore(FCards.PlayerScore);
frmScore.ShowModal;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -