⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 carddraw.pas

📁 这是一个扑克牌游戏。 1.抓有黑桃7 的玩家首先出黑桃7。 2.然后按逆时针方向出牌。每位玩家依次出牌
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{
接龙游戏的牌局图像处理

牌索引 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 + -