在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
游戏的界面 主要的功能实现 1 键盘消息 program Project1; {$APPTYPE CONSOLE} uses SysUtils, windows, uConsoleClass in 'uConsoleClass.pas', uSnake in 'uSnake.pas'; // 参考 /// http://blog.csdn.net/haiou327/article/details/5695237 var MyMsg : TMsg; begin while windows.GetMessage(MyMsg, 0, 0, 0) do begin DispatchMessage(MyMsg); end; end.
2 定时器 这里用的是API procedure TimerProc(window : Hwnd ; message,idEvent :UInt; dwTime: dword);stdcall; begin if Snake.StartSnake then Snake.MoveSnake(); end;
3 蛇控制单元 unit uSnake; interface uses Windows, classes, uConsoleClass, ExtCtrls; const GAMEROW = 16; GAMECOL = 54; TIMERINTERVAL = 300; type TMoveDir = (MD_Right, MD_Left, MD_Up, MD_Down); TPointType = (PT_Head, PT_Body, PT_Tail, PT_Food); TGamePoint = record Row : byte; Col : byte; PointType : TPointType; end; PGamePoint = ^TGamePoint; TReadKeyThread = Class(TThread) private FMoveDir : TMoveDir; FStartRead : boolean; FPause : boolean; procedure SetStartRead(const Value: boolean); public property Pause : boolean read FPause write FPause; property StartRead : boolean read FStartRead write SetStartRead; property MoveDir : TMoveDir read FMoveDir write FMoveDir; protected procedure Execute; override; end; TSnake = class private //FGameMap : array[0..GAMEROW - 1, 0..GAMECOL - 1] of byte; FFoodPoint : PGamePoint; FSnakePointList : TList; FLastPoint : PGamePoint; FMyConsole : TConsoleControl; FStartSnake : boolean; FReadKeyThread : TReadKeyThread; FEatFoodCount : integer; // FScores : integer; procedure InitGameMap(); procedure FreeSnakeList(); function CheckInSnake(Row, Col: integer): boolean; procedure PrintSnake(); function GetSnakeBodyType(bodyType: TPointType): PGamePoint; procedure GetFood(); procedure ShowScores(add: boolean = false); procedure Start(); function CheckGameOver(): boolean; procedure GameOver(); function EatFood(): boolean; function GetMoveDir(): TMoveDir; property Dir: TMoveDir read GetMoveDir; property StartSnake: boolean read FStartSnake write FStartSnake; public constructor Create(); destructor Destroy;override; procedure StartGame(); procedure MoveSnake(); function ThreadPause(): boolean; end; implementation uses SysUtils; var Snake : TSnake; FTimer : Integer; procedure TimerProc(window : Hwnd ; message,idEvent :UInt; dwTime: dword);stdcall; begin if Snake.StartSnake then Snake.MoveSnake(); end; { TSnake } function TSnake.CheckGameOver: boolean; var Head: PGamePoint; I: integer; P: PGamePoint; begin Result := false; Head := GetSnakeBodyType(PT_Head); // FMyConsole.SetCursorTo(0, 16); // FMyConsole.WriteText('Row: ' + inttostr(Head^.Row) + ' Col: ' + inttostr(Head^.Col)); if Dir = MD_Up then begin if Head^.Row = 1 then Result := true; end; // 判断撞到上下的墙 if (Head^.Row < 1) or (Head^.Row > GAMEROW - 3) then Result := true; // 判断撞到左右的墙 if (Head^.Col < 3) or (Head^.Col > GAMECOL - 6) then Result := true; // 判断是否撞到自己 for I := 2 to FSnakePointList.Count - 1 do begin P := FSnakePointList.Items[I]; case Dir of MD_Right: begin if (Head^.Col + 1 = P^.Col) and (Head^.Row = P^.Row) then Result := true; end; MD_Left: begin if (Head^.Col - 1 = P^.Col) and (Head^.Row = P^.Row) then Result := true; end; MD_Up: begin if (Head^.Row - 1 = P^.Row) and (Head^.Col = P^.Col) then Result := true; end; MD_Down: begin if (Head^.Row + 1 = P^.Row) and (Head^.Col = P^.Col) then Result := true; end; end; end; end; function TSnake.CheckInSnake(Row, Col: integer): boolean; var P: PGamePoint; I: integer; begin Result := false; for I := 0 to FSnakePointList.Count - 1 do begin P := FSnakePointList.Items[I]; if (P^.Row = Row) and (P^.Col= Col) then begin Result := true; break; end; end; end; constructor TSnake.Create(); begin FReadKeyThread := TReadKeyThread.Create(true); FSnakePointList := TList.Create(); New(FFoodPoint); New(FLastPoint); FMyConsole:= TConsoleControl.Create; FMyConsole.SetWindowTitle('【贪吃蛇】 V1.0'); InitGameMap(); end; destructor TSnake.Destroy; begin Dispose(FFoodPoint); Dispose(FLastPoint); FreeAndNil(FSnakePointList); FMyConsole.Free; FReadKeyThread.Free(); inherited; end; function TSnake.EatFood: boolean; var Head : PGamePoint; begin Result := false; Head := GetSnakeBodyType(PT_Head); if (Head^.Row = FFoodPoint^.Row) and (Head^.Col = FFoodPoint^.Col) then begin ShowScores(true); Result := true; end; ShowScores(); end; procedure TSnake.FreeSnakeList; var P: PGamePoint; Index: integer; begin if FSnakePointList.Count > 0 then begin repeat Index := FSnakePointList.Count - 1; P := FSnakePointList.Items[Index]; FSnakePointList.Delete(Index); Dispose(P); until FSnakePointList.Count = 0; end; end; procedure TSnake.GameOver; var S: string; begin StartSnake := false; FReadKeyThread.StartRead := false; // FMyConsole.SetCursorTo(0, 16); FMyConsole.WriteText(' '); FMyConsole.SetCursorTo(0, 16); FMyConsole.WriteText('游戏结束重新开始吗? (y/n):'); Readln(S); if LowerCase(S) = 'y' then begin //FMyConsole.SetCursorTo(0, 16); //FMyConsole.WriteText('游戏开始 '); InitGameMap(); Start(); end; end; procedure TSnake.GetFood; begin Randomize; repeat FFoodPoint^.Row := Random(GAMEROW - 7) + 5; FFoodPoint^.Col := Random(GAMECOL - 10) + 5; until not CheckInSnake(FFoodPoint^.Row, FFoodPoint^.Col); FMyConsole.SetForegroundColor(true, false, true, false); FMyConsole.SetCursorTo(FFoodPoint^.Col, FFoodPoint^.Row); FMyConsole.WriteText('O'); end; function TSnake.GetMoveDir: TMoveDir; begin Result := FReadKeyThread.MoveDir; end; function TSnake.GetSnakeBodyType(bodyType: TPointType): PGamePoint; var I: integer; begin Result := nil; for I := 0 to FSnakePointList.Count - 1 do begin Result := FSnakePointList.Items[I]; if Result.PointType = bodyType then break; end; end; procedure TSnake.InitGameMap; var // I, J: integer; P: PGamePoint; begin FMyConsole.ClearScreen; // for I := 0 to GAMEROW - 1 do // begin // for J := 0 to GAMECOL - 1 do // begin // if (I = 0) or (I = GAMEROW - 1) then // FGameMap[I][J] := 1 // else // FGameMap[I][J] := 0; // // if (J = 0) or (J = 1) or (J = GAMECOL - 1 ) or (J = GAMECOL - 2 ) then // FGameMap[I][J] := 1 // else // FGameMap[I][J] := 0; // end; // end; FreeSnakeList(); // 头 先添加 New(P); P^.Row := 2; P^.Col := 7; P^.PointType := PT_Head; FSnakePointList.Add(P); // 身体 New(P); P^.Row := 2; P^.Col := 6; P^.PointType := PT_Body; FSnakePointList.Add(P); New(P); P^.Row := 2; P^.Col := 5; P^.PointType := PT_Body; FSnakePointList.Add(P); New(P); P^.Row := 2; P^.Col := 4; P^.PointType := PT_Body; FSnakePointList.Add(P); New(P); P^.Row := 2; P^.Col := 3; P^.PointType := PT_Tail; FSnakePointList.Add(P); // // 蛇的初始位置 // for J := 1 to 5 do // FGameMap[1][J] := 1; // 食物初始位置 // FFoodPoint^.Row := 10; // FFoodPoint^.Col := 30; // FFoodPoint^.PointType := PT_Food; // FGameMap[10][30] := 1; FMyConsole.SetCursorTo(0, 0); FMyConsole.SetForegroundColor(true, false, false, false); FMyConsole.WriteTextLine('┏━━━━━━━━━━━━━━━━━━━━━━━━┓'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┃ ┃'); FMyConsole.WriteTextLine('┗━━━━━━━━━━━━━━━━━━━━━━━━┛'); GetFood(); end; procedure TSnake.MoveSnake; var Head : PGamePoint; Tail : PGamePoint; P1, P2: PGamePoint; I : integer; NewBody: PGamePoint; eat: boolean; begin if ThreadPause then begin FMyConsole.SetCursorTo(0, 16); FMyConsole.WriteText('游戏已暂停请按空格键继续... '); end else begin if CheckGameOver() then begin GameOver(); end else begin eat := EatFood(); //保存最后一个要擦除的点 Tail := GetSnakeBodyType(PT_Tail); FLastPoint^.Row := Tail^.Row; FLastPoint^.Col := Tail^.Col; if eat then begin New(NewBody); NewBody^.Row := Tail^.Row; NewBody^.Col := Tail^.Col; NewBody^.PointType := PT_Tail; FSnakePointList.add(NewBody); Tail^.PointType := PT_Body; GetFood(); end; // 移动蛇的位置 for I := FSnakePointList.Count - 1 downto 1 do begin P1 := FSnakePointList.Items[I]; P2 := FSnakePointList.Items[I - 1]; P1^.Row := P2^.Row; P1^.Col := P2^.Col; end; Head := GetSnakeBodyType(PT_Head); case Dir of MD_Right: Inc(Head^.Col); MD_Left : Dec(Head^.Col); MD_Up : Dec(Head^.Row); MD_Down : Inc(Head^.Row); end; PrintSnake(); // 清空蛇尾 if FStartSnake and not eat then begin FMyConsole.SetCursorTo(FLastPoint^.Col, FLastPoint^.Row); FMyConsole.WriteText(' '); end; end; end; end; procedure TSnake.PrintSnake; var P: PGamePoint; I: integer; begin FMyConsole.SetForegroundColor(false, true, false, false); for I := 0 to FSnakePointList.Count - 1 do begin P := FSnakePointList.Items[I]; FMyConsole.SetCursorTo(P^.Col, P^.Row); case P^.PointType of PT_Head: FMyConsole.WriteText('#'); PT_Body: FMyConsole.WriteText('*'); PT_Tail: FMyConsole.WriteText('*'); end; end; // FMyConsole.WriteTextLine('┏━━━━━━━━━━━━━━━━━━━━━━━━┓'); // FMyConsole.WriteTextLine('┃****# ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ O ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┃ ┃'); // FMyConsole.WriteTextLine('┗━━━━━━━━━━━━━━━━━━━━━━━━┛'); // 14 行 48 列 end; procedure TSnake.ShowScores(add: boolean = false); var S: string; begin // FEatFoodCount : integer; // FScores : integer; if add then begin Inc(FEatFoodCount); end; S := Format('完成食物个数: %d 得分数: %d ', [FEatFoodCount, 10 * FEatFoodCount]); FMyConsole.SetCursorTo(0, 16); FMyConsole.WriteText(S); end; procedure TSnake.Start; begin FEatFoodCount := 0; //FScores := 0; StartSnake := true; FReadKeyThread.StartRead := true; end; procedure TSnake.StartGame; var S: string; begin PrintSnake(); FMyConsole.SetCursorTo(0, 16); FMyConsole.WriteText('现在开始游戏吗? (y/n):'); Readln(S); if LowerCase(S) = 'y' then begin // FMyConsole.SetCursorTo(0, 16); // FMyConsole.WriteText('开始游戏 '); Start(); end; end; function TSnake.ThreadPause: boolean; begin Result := FReadKeyThread.Pause; end; { TReadKeyThread } procedure TReadKeyThread.Execute; var arrInputRecs : array[0..9] of TInputRecord; dwCur, dwCount : DWORD; hInput : THandle; begin hInput := GetStdHandle(STD_INPUT_HANDLE); while TRUE do begin ReadConsoleInput(hInput, arrInputRecs[0], 10, dwCount); for dwCur := 0 to 10 - 1 do begin if self.Terminated then break; case arrInputRecs[dwCur].EventType of KEY_EVENT: begin with arrInputRecs[dwCur].Event.KeyEvent do begin if bKeyDown = true then begin case wVirtualKeyCode of VK_Space: begin Pause := not Pause; end; VK_Left: begin if (MoveDir <> MD_Left) and (MoveDir <> MD_Right) then begin if not FPause then MoveDir := MD_Left; end; end; VK_Right: begin if (MoveDir <> MD_Right) and (MoveDir <> MD_Left) then begin if not FPause then MoveDir := MD_Right; end; end; VK_Up: begin if (MoveDir <> MD_Up) and (MoveDir <> MD_Down) then begin if not FPause then MoveDir := MD_Up; end; end; VK_Down: begin if (MoveDir <> MD_Up) and (MoveDir <> MD_Down) then begin if not FPause then MoveDir := MD_Down; end; end; end; end; end; end; end; end; end; end; procedure TReadKeyThread.SetStartRead(const Value: boolean); begin FStartRead := Value; if FStartRead then begin MoveDir := MD_Right; FPause := false; Resume; end else Suspend; end; initialization Snake := TSnake.Create; Snake.StartGame(); FTimer := SetTimer(0, 0, TIMERINTERVAL, @TimerProc); finalization KillTimer(0, FTimer); Snake.Free(); end. 4 控制台单元 这个单元是网上的
unit uConsoleClass; interface uses Windows; type TConsoleControl = Class private FhStdIn : THandle; // Handle to the standard input FhStdOut : THandle; // Handle to the standard output FhStdErr : THandle; // Handle to the standard error (Output) FbConsoleAllocated : Boolean; // Creation Flag FBgAttrib : Cardinal; // Currently set BackGround Attribs. FFgAttrib : Cardinal; // Currently set ForeGround Attribs. public (* Creates a new consolewindow, or connects the current window *) constructor Create; destructor Destroy;override; (* Cleanup of the class structures 全部评论
专题导读
上一篇:理解 Delphi 的类(十) - 深入方法[14] - 在TForm1 类内声明的方法发布时间:2022-07-18下一篇:DelphiRichEdit读取剪切板发布时间:2022-07-18热门推荐
热门话题
阅读排行榜
|
请发表评论