<aside> ๐ค
๋ชจ๋ ๊ฒ๋ฅผ ๋ด๋นํ๋ ์คํฌ๋ฆฝํธ
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
{ ์ค๋ธ์ ํธ ๋ชฉ๋ก }
TObjectType = (ObjA, ObjB, ObjC, ObjD, ObjMouse, ObjFollow);
{
ObjA: Small & Fast
ObjB: Normal Obj
ObjC: Random Direction Move
ObjD: Rotating Object
ObjFollow: Mouse Following Enemy Object
ObjMouse: Mouse Following Object
}
{ ๊ธฐ๋ณธ ์ค๋ธ์ ํธ }
TBaseObject = class
public
ObjType: TObjectType;
X, Y: Integer;
Width, Height: Integer;
SpeedX, SpeedY: Integer;
IsDead: Boolean;
constructor Create; virtual;
procedure Move; virtual;
property Dead: Boolean read IsDead write IsDead;
end;
{ A ์ค๋ธ์ ํธ }
TObjA = class(TBaseObject)
constructor Create; override;
procedure Move; override;
end;
{ B ์ค๋ธ์ ํธ }
TObjB = class(TBaseObject)
constructor Create; override;
procedure Move; override;
end;
{ C ์ค๋ธ์ ํธ }
TObjC = class(TBaseObject)
private
MoveTime: Integer; // ์ด๋ ์๊ฐ
StopTime: Integer; // ์ ์ง ์๊ฐ
IsStopped: Boolean;
SpeedOptionsX: array[0..6] of Integer;
SpeedOptionsY: array[0..6] of Integer;
MaxMoveTime: Integer;
MaxStopTime: Integer;
public
constructor Create; override;
procedure Move; override;
end;
{ D ์ค๋ธ์ ํธ }
TObjD = class(TBaseObject)
private
CenterX, CenterY: Integer; // ํ์ ์ค์ฌ
Radius: Integer; // ํ์ ๋ฐ๊ฒฝ
Angle: Double; // ํ์ฌ ํ์ ๊ฐ๋
AngularSpeed: Double; // ๊ฐ ์๋
public
constructor Create; override;
procedure Move; override;
end;
{ Follow ์ค๋ธ์ ํธ }
TObjFollow = class(TBaseObject)
private
CurSpeed: Double;
MaxSpeed: Double;
SpeedUpInterval: Integer;
SpeedUpTimer: Integer;
public
constructor Create; override;
procedure Move; override;
end;
{ Mouse ์ค๋ธ์ ํธ }
TObjMouse = class(TBaseObject)
public
constructor Create; override;
procedure Move; override;
procedure SetPosition(AX, AY: Integer);
end;
TForm1 = class(TForm)
Panel1: TPanel;
Timer1: TTimer;
TimerSpawn: TTimer;
PaintBox1: TPaintBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure TimerSpawnTimer(Sender: TObject);
procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
private
Objects: TList;
MouseFollower: TObjMouse;
GameOver: Boolean;
Score: Integer;
ScoreTimer: Integer;
MaxScore: Integer;
BlackHoleCenter: TPoint;
IsBlackHoleActive: Boolean;
BlackHoleTimer: Integer;
BlackHoleDuration: Integer;
IsBurstActive: Boolean;
BurstDuration: Integer;
BlackHoleSpawnTimer: Integer;
BlackHoleSpawnInterval: Integer;
function CheckCollision(obj1, obj2: TBaseObject): Boolean;
procedure CreateRandomObject;
procedure CreateFollowObject;
procedure ResetGame;
procedure UpdateScore;
procedure RemoveFollowObjects;
// ๋ธ๋ํ ํจ๊ณผ ๊ด๋ จ ํจ์
procedure ActivateBlackHole(const APoint: TPoint; ATriggeredObj: TObjFollow = nil);
procedure UpdateBlackHoleEffect;
procedure DrawBlackHoleEffect;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TBaseObject }
constructor TBaseObject.Create;
begin
inherited Create;
{ ๊ธฐ๋ณธ ์ค์ }
Width := 10;
Height := 10;
SpeedX := 0;
SpeedY := 0;
IsDead := False;
{ Form1 ๋ฐ Panel1์ด ์ ํจํ ๊ฒฝ์ฐ, ๋ฌด์์ ์์น์ ์์ฑ }
if Assigned(Form1) and Assigned(Form1.Panel1) then
begin
X := Random(Form1.Panel1.Width - Width);
Y := Random(Form1.Panel1.Height - Height);
end
else
begin
{ ๊ธฐ๋ณธ ๊ฐ }
X := Random(400);
Y := Random(300);
end;
end;
procedure TBaseObject.Move;
var
DeltaX, DeltaY, Distance: Double;
EffectSpeed: Double;
begin
{ Form1 ๋ฐ Panel1์ด ์ ํจํ ๊ฒฝ์ฐ }
if not (Assigned(Form1) and Assigned(Form1.Panel1)) then Exit;
{ ObjMouse๋ ๋ชจ๋ ํจ๊ณผ ๋ฌด์ }
if ObjType = ObjMouse then
begin
Exit;
end;
{ ๋ธ๋ํ ์์ฑ ์ }
if Form1.IsBlackHoleActive then
begin
{ ๋ธ๋ํ์ ์ค์ฌ์ผ๋ก ๋์ด๋น๊ฒจ์ง }
DeltaX := Form1.BlackHoleCenter.X - (X + Width div 2);
DeltaY := Form1.BlackHoleCenter.Y - (Y + Height div 2);
Distance := Sqrt(DeltaX * DeltaX + DeltaY * DeltaY);
{ ๋ธ๋ํ์ด ๋์ด๋น๊ธฐ๋ ์๋ ์กฐ์ }
EffectSpeed := 20;
{ ๋ธ๋ํ๊ณผ์ ๊ฑฐ๋ฆฌ๊ฐ ๋๋ฌด ๊ฐ๊น์ฐ๋ฉด ์ค์์ ๋ฐฐ์นํจ }
if Distance < EffectSpeed then
begin
X := Form1.BlackHoleCenter.X - Width div 2;
Y := Form1.BlackHoleCenter.Y - Height div 2;
SpeedX := 0;
SpeedY := 0;
end
{ ๊ฐ๊น์ง ์์ผ๋ฉด ๊ณ์ ์ด๋ }
else if Distance > 0 then
begin
SpeedX := Round(DeltaX / Distance * EffectSpeed);
SpeedY := Round(DeltaY / Distance * EffectSpeed);
end
{ ์ ํํ ์ค์์ ์ค๋ฉด ๋ฉ์ถค }
else
begin
SpeedX := 0;
SpeedY := 0;
end;
Inc(X, SpeedX);
Inc(Y, SpeedY);
end
{ ๋ฒ์คํธ ์ค์ผ ์ }
else if Form1.IsBurstActive then
begin
{ ๋ธ๋ํ์ ์ค์ฌ์ ์์ ๋ฉ๋ฆฌ ๋ฉ๋ ค๋จ (ํ์ฌ ์์น๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฐฉํฅ ์ค์ ) }
DeltaX := (X + Width div 2) - Form1.BlackHoleCenter.X;
DeltaY := (Y + Height div 2) - Form1.BlackHoleCenter.Y;
Distance := Sqrt(DeltaX * DeltaX + DeltaY * DeltaY);
{ ๋ฐ๋ ค๋๋ ์๋ ์กฐ์ }
EffectSpeed := 30;
{ ๋ธ๋ํ๊ณผ์ ๊ฑฐ๋ฆฌ์ ๋ฐ๋ฅธ ์๋ ์กฐ์ }
{ ๋๋ฌด ๊ฐ๊น์ฐ๋ฉด ๋๋คํ ๋ฐฉํฅ์ผ๋ก ๋ฐ๋ ค๋จ }
if Distance < 10 then
begin
DeltaX := Random(200) - 100;
DeltaY := Random(200) - 100;
Distance := Sqrt(DeltaX * DeltaX + DeltaY * DeltaY);
end;
if Distance > 0 then
begin
SpeedX := Round(DeltaX / Distance * EffectSpeed);
SpeedY := Round(DeltaY / Distance * EffectSpeed);
end
{ ์ ํํ ์ค์ฌ์ด๋ฉด ๋๋คํ๊ฒ ๋ฐ๋ ค๋จ }
else
begin
SpeedX := Random(20) - 10;
SpeedY := Random(20) - 10;
end;
Inc(X, SpeedX);
Inc(Y, SpeedY);
{ ๋ฒ์คํธ ์ค์๋ ๋ฒฝ์ ๋ฟ์๋ ์ ๊ฑฐ X -> ์ถฉ๋ ๋ก์ง X }
end
{ ์ผ๋ฐ ์ด๋ ์ }
else
begin
{ ํ์ฌ ์๋ ๋งํผ ์ด๋ }
Inc(X, SpeedX);
Inc(Y, SpeedY);
{ ๋ฒฝ์ ๋ฟ์์ ๊ฒฝ์ฐ ํ์ }
if X < 0 then
begin
X := 0;
SpeedX := -SpeedX;
end;
if Y < 0 then
begin
Y := 0;
SpeedY := -SpeedY;
end;
if X > Form1.Panel1.Width - Width then
begin
X := Form1.Panel1.Width - Width;
SpeedX := -SpeedX;
end;
if Y > Form1.Panel1.Height - Height then
begin
Y := Form1.Panel1.Height - Height;
SpeedY := -SpeedY;
end;
end;
end;
{ TObjA }
constructor TObjA.Create;
begin
inherited Create; // Base์ Create ์ฌ์ฉ
ObjType := ObjA;
Width := 50;
Height := 50;
SpeedX := 10;
SpeedY := 10;
end;
procedure TObjA.Move;
begin
inherited Move; // Base์ Move ์ฌ์ฉ
end;
{ TObjB }
constructor TObjB.Create;
begin
inherited Create; // Base์ Create ์ฌ์ฉ
ObjType := ObjB;
Width := 75;
Height := 75;
SpeedX := 5;
SpeedY := 5;
end;
procedure TObjB.Move;
begin
inherited Move; // Base์ Move ์ฌ์ฉ
end;
{ TObjC }
constructor TObjC.Create;
begin
inherited Create; // Base์ Create ์ฌ์ฉ
ObjType := ObjC;
Width := 35;
Height := 35;
{ ์๋ ๋ฒ์ ์ง์ }
SpeedOptionsX[0] := -30;
SpeedOptionsX[1] := -15;
SpeedOptionsX[2] := -5;
SpeedOptionsX[3] := 0;
SpeedOptionsX[4] := 5;
SpeedOptionsX[5] := 15;
SpeedOptionsX[6] := 30;
SpeedOptionsY[0] := -30;
SpeedOptionsY[1] := -15;
SpeedOptionsY[2] := -5;
SpeedOptionsY[3] := 0;
SpeedOptionsY[4] := 5;
SpeedOptionsY[5] := 15;
SpeedOptionsY[6] := 30;
{ ์ง์ ํ ์๋ ๋ฒ์์์ ๋๋คํ ๊ฐ ์ง์ }
SpeedX := SpeedOptionsX[Random(Length(SpeedOptionsX))];
SpeedY := SpeedOptionsY[Random(Length(SpeedOptionsY))];
MoveTime := 0;
StopTime := 0;
IsStopped := False;
MaxMoveTime := 0;
MaxStopTime := 0;
end;
procedure TObjC.Move;
begin
{ ๋ธ๋ํ ๋ฐ๋ ์ Base์ Move ์ฌ์ฉ }
if Form1.IsBlackHoleActive or Form1.IsBurstActive then
begin
inherited Move;
end
{ ๋ธ๋ํ์ด ๋ฐ๋๋์ง ์์์ ๋๋ง C๋ง์ Move ์ฌ์ฉ }
else
begin
{ ๋ฉ์ถฐ์์ ๋ }
if IsStopped then
begin
{ ๋ฉ์ถ ์๊ฐ ์ง์ }
if MaxStopTime = 0 then
MaxStopTime := 5 + Random(16);
Inc(StopTime);
{ ๋ฉ์ถฐ์ผ ํ ์๊ฐ๋์ ๋ฉ์ถ ๋ค }
if StopTime >= MaxStopTime then
begin
{ ์๋๋ฅผ ๋ค์ ์ง์ ํ๊ณ ๋ฉ์ถ๊ธฐ ์ค์ง }
SpeedX := SpeedOptionsX[Random(Length(SpeedOptionsX))];
SpeedY := SpeedOptionsY[Random(Length(SpeedOptionsY))];
StopTime := 0;
MaxStopTime := 0;
IsStopped := False;
end;
end
{ ์์ง์ผ ๋ }
else
begin
inherited Move;
{ ์ด๋ํ ์๊ฐ ์ง์ }
if MaxMoveTime = 0 then
MaxMoveTime := 10 + Random(51);
{ ์ด๋ ์๊ฐ ์ฆ๊ฐ }
Inc(MoveTime);
{ ์ด๋ํ ์๊ฐ๋งํผ ์์ง์ด๋ฉด ์ ์ง }
if MoveTime >= MaxMoveTime then
begin
SpeedX := 0;
SpeedY := 0;
MoveTime := 0;
MaxMoveTime := 0;
IsStopped := True;
end;
end;
end;
end;
{ TObjD }
constructor TObjD.Create;
begin
inherited Create;
ObjType := ObjD;
Width := 30;
Height := 30;
if Assigned(Form1) and Assigned(Form1.Panel1) then
begin
{ ์ค์ ์์น ์กฐ์ }
CenterX := Random(Form1.Panel1.Width - Width) + Width div 2;
CenterY := Random(Form1.Panel1.Height - Height) + Height div 2;
end
else
begin
{ ๊ธฐ๋ณธ ๊ฐ }
CenterX := Random(400) + 15;
CenterY := Random(300) + 15;
end;
{ Radius ์ด๊ธฐ ๊ฐ ์ค์ (5 ~ 50) }
Radius := 5 + Random(46);
{ ์ด๊ธฐ ๊ฐ๋ ์ค์ }
Angle := 0;
{ AngularSpeed ์ด๊ธฐ ๊ฐ ์ค์ (Pi/60 ~ Pi/15) }
AngularSpeed := (Pi / 60) + (Random * (Pi / 15 - Pi / 60));
SpeedX := 0;
SpeedY := 0;
IsDead := False;
end;
procedure TObjD.Move;
var
NewX, NewY: Integer;
begin
if IsDead then Exit;
{ ๋ธ๋ํ ๋ฐ ๋ฒ์คํธ ์ค์ด๋ฉด Base์ Move ์ฌ์ฉ }
if Form1.IsBlackHoleActive or Form1.IsBurstActive then
begin
inherited Move;
end
{ ์ผ๋ฐ ์ด๋ ์ }
else
begin
if not (Assigned(Form1) and Assigned(Form1.Panel1)) then Exit;
{ ๊ฐ์ ๊ณ์ ๋ฒ๋ฆฌ๋ฉด์ ๋น๊ธ๋น๊ธ ๋๊ฒ ํจ }
Radius := Radius + 1;
if Radius > (Form1.Panel1.Width div 2) then
Radius := 10;
Angle := Angle + AngularSpeed;
if Angle > 2 * Pi then
Angle := Angle - 2 * Pi;
NewX := CenterX + Round(Radius * Cos(Angle));
NewY := CenterY + Round(Radius * Sin(Angle));
{ ๋ฒฝ์ ๋ฟ์ผ๋ฉด ์ ๊ฑฐ }
if (NewX < 0) or (NewY < 0) or
(NewX > Form1.Panel1.Width - Width) or
(NewY > Form1.Panel1.Height - Height) then
begin
IsDead := True;
Exit;
end;
X := NewX;
Y := NewY;
{ ๋ค๋ฅธ ์ค๋ธ์ ํธ๋ค ๊ฐ์ ์ถฉ๋ ๋ฌด์ -> ์ถฉ๋ ๋ก์ง X }
end;
end;
{ TObjFollow }
constructor TObjFollow.Create;
begin
inherited Create;
ObjType := ObjFollow;
Width := 40;
Height := 40;
{ ์ด๊ธฐ ์๋ }
CurSpeed := 5.0;
{ ์๋ ์ฆ๊ฐ ๊ฐ๊ฒฉ (0.5์ด๋ง๋ค) }
SpeedUpInterval := Round(500 / Form1.Timer1.Interval);
{ Interval์ด 0์ด ๋๋ ๊ฒ์ ๋ฐฉ์งํจ }
if SpeedUpInterval = 0 then SpeedUpInterval := 1;
{ ์๋ ์ฆ๊ฐ ํ์ด๋จธ ์ค์ }
SpeedUpTimer := 0;
{ ์ต๋ ์๋ ์ ํ }
MaxSpeed := 30.0;
end;
procedure TObjFollow.Move;
var
TargetX, TargetY: Integer;
DeltaX, DeltaY: Double;
Distance: Double;
begin
if IsDead then Exit;
if not (Assigned(Form1) and Assigned(Form1.Panel1) and Assigned(Form1.MouseFollower)) then Exit;
if not (Form1.IsBlackHoleActive or Form1.IsBurstActive) then
begin
{ ๋ง์ฐ์ค ์์น ๊ฐ์ ธ์ค๊ธฐ }
TargetX := Form1.MouseFollower.X + Form1.MouseFollower.Width div 2;
TargetY := Form1.MouseFollower.Y + Form1.MouseFollower.Height div 2;
{ Follow์ ์ค์ฌ์ }
DeltaX := TargetX - (X + Width div 2);
DeltaY := TargetY - (Y + Height div 2);
{ ๋ง์ฐ์ค์์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ }
Distance := Sqrt(DeltaX * DeltaX + DeltaY * DeltaY);
{ ๋ง์ฐ์ค์์ ๊ฑฐ๋ฆฌ๊ฐ 0์ด ์๋ ๋ }
if Distance > 0 then
begin
{ ์๋ ์ง์ (๋ฐฉํฅ๋ ๊ฐ์ด ์ง์ ) }
SpeedX := Round(DeltaX / Distance * CurSpeed);
SpeedY := Round(DeltaY / Distance * CurSpeed);
end
else
begin
SpeedX := 0;
SpeedY := 0;
end;
{ ์ด๋ }
Inc(X, SpeedX);
Inc(Y, SpeedY);
{ ์๋๋ฅผ ์ ์ง์ ์ผ๋ก ์ฆ๊ฐ }
Inc(SpeedUpTimer);
if SpeedUpTimer >= SpeedUpInterval then
begin
{ 0.5์ฉ ์ฆ๊ฐ }
CurSpeed := CurSpeed + 0.5;
{ ์ต๋ ์๋ ์ ํ }
if CurSpeed > MaxSpeed then
CurSpeed := MaxSpeed;
SpeedUpTimer := 0;
end;
end
{ ๋ธ๋ํ ๋ฐ ๋ฒ์คํธ ์ค์๋ Base์์ Move๋ฅผ ํธ์ถํด ๋๋ ค๊ฐ๊ฒ ํจ }
else
begin
inherited Move;
end;
end;
{ TObjMouse }
constructor TObjMouse.Create;
begin
inherited Create;
ObjType := ObjMouse;
Width := 25;
Height := 25;
{ ์ด๊ธฐ ์์น ์ค์ }
if Assigned(Form1) and Assigned(Form1.Panel1) then
begin
X := Form1.Panel1.Width div 2 - Width div 2;
Y := Form1.Panel1.Height div 2 - Height div 2;
end
else
begin
{ ๊ธฐ๋ณธ ๊ฐ }
X := 200;
Y := 150;
end;
end;
procedure TObjMouse.Move;
begin
// ๋ง์ฐ์ค ์ค๋ธ์ ํธ๋ Move์์ ์๋ฌด๊ฒ๋ ํ์ง ์์
// ์์น๋ SetPosition์ผ๋ก๋ง ์ค์ ๋จ
end;
{ ๋ง์ฐ์ค ์ค๋ธ์ ํธ ์์น ์ค์ }
procedure TObjMouse.SetPosition(AX, AY: Integer);
begin
{ ๋ง์ฐ์ค ์์น๋ก ์ด๋ }
X := AX - Width div 2;
Y := AY - Height div 2;
end;
{ TForm1 }
{ ์ ์ ์
๋ฐ์ดํธ }
procedure TForm1.UpdateScore;
begin
Inc(ScoreTimer);
{ ์ฝ 1์ด๋ง๋ค ์ ์ ์ฆ๊ฐ }
if ScoreTimer >= Round(1000 / Timer1.Interval) then
begin
Inc(Score);
ScoreTimer := 0;
end;
end;
{ ์ค๋ธ์ ํธ ์ถฉ๋ ์ฒดํฌ }
function TForm1.CheckCollision(obj1, obj2: TBaseObject): Boolean;
begin
Result := (obj1.X < obj2.X + obj2.Width) and
(obj1.X + obj1.Width > obj2.X) and
(obj1.Y < obj2.Y + obj2.Height) and
(obj1.Y + obj1.Height > obj2.Y);
end;
{ ๊ฒ์ ์ด๊ธฐํ }
procedure TForm1.ResetGame;
var
i: Integer;
begin
{ ๋ง์ฐ์ค ์ค๋ธ์ ํธ๋ฅผ ์ ์ธํ ๋ชจ๋ ์ค๋ธ์ ํธ ์ ๊ฑฐ }
if Assigned(Objects) then
begin
for i := Objects.Count - 1 downto 0 do
begin
if TBaseObject(Objects[i]).ObjType <> ObjMouse then
begin
TObject(Objects[i]).Free;
Objects.Delete(i);
end;
end;
end;
{ ๋ง์ฐ์ค ์ค๋ธ์ ํธ ์์น ์ด๊ธฐํ }
if Assigned(MouseFollower) then
begin
MouseFollower.X := Panel1.Width div 2 - MouseFollower.Width div 2;
MouseFollower.Y := Panel1.Height div 2 - MouseFollower.Height div 2;
end;
{ ์ด๊ธฐ ์ค๋ธ์ ํธ ์์ฑ }
CreateRandomObject;
{ ๊ฒ์ ์ด๊ธฐํ }
GameOver := False;
if Score > MaxScore then
MaxScore := Score;
Score := 1;
ScoreTimer := 0;
{ ๋ธ๋ํ ์ด๊ธฐํ }
IsBlackHoleActive := False;
IsBurstActive := False;
BlackHoleTimer := 0;
BlackHoleSpawnTimer := 0;
{ ํ์ด๋จธ ์ด๊ธฐํ }
Timer1.Enabled := True;
TimerSpawn.Enabled := True;
end;
{ ์ค๋ธ์ ํธ ์ํ }
procedure TForm1.CreateRandomObject;
var
obj: TBaseObject;
ObjTypeIndex: Integer;
i: Integer;
begin
{ ์ค๋ธ์ ํธ 3๊ฐ ์ํ }
for i := 0 to 2 do
begin
// ObjMouse์ ObjFollow๋ฅผ ์ ์ธํ ํ์
๋ค ์ค ์ ํ (ObjA, ObjB, ObjC, ObjD)
ObjTypeIndex := Random(Ord(ObjMouse));
{ ์ค๋ธ์ ํธ ์ํ }
case TObjectType(ObjTypeIndex) of
ObjA: obj := TObjA.Create;
ObjB: obj := TObjB.Create;
ObjC: obj := TObjC.Create;
ObjD: obj := TObjD.Create;
else
obj := TObjA.Create;
end;
Objects.Add(obj);
end;
end;
{ ObjFollow ์ค๋ธ์ ํธ ์์ฑ }
procedure TForm1.CreateFollowObject;
var
obj: TBaseObject;
begin
obj := TObjFollow.Create;
Objects.Add(obj);
end;
{ ObjFollow ์ ๊ฑฐ }
procedure TForm1.RemoveFollowObjects;
var
i: Integer;
obj: TBaseObject;
begin
{ ์ธ๋ฑ์ค๊ฐ ๊ผฌ์ด์ง ์๊ฒ ์ญ์ ์กฐํ }
for i := Objects.Count - 1 downto 0 do
begin
obj := TBaseObject(Objects[i]);
{ ObjFollow๋ฉด }
if obj.ObjType = ObjFollow then
begin
{ ์ ๊ฑฐ }
Objects.Delete(i);
obj.Free;
end;
end;
end;
{ ๋ธ๋ํ ํ์ฑํ ํจ์ }
procedure TForm1.ActivateBlackHole(const APoint: TPoint; ATriggeredObj: TObjFollow = nil);
begin
if not IsBlackHoleActive then
begin
{ ๋ธ๋ํ ์์ฑ }
IsBlackHoleActive := True;
BlackHoleTimer := 0;
BlackHoleCenter := APoint;
end;
end;
{ ๋ธ๋ํ ๋ฐ ํญ๋ฐ ํจ๊ณผ ์
๋ฐ์ดํธ ํจ์ }
procedure TForm1.UpdateBlackHoleEffect;
begin
{ ๋ธ๋ํ ์์ฑ ์ }
if IsBlackHoleActive then
begin
Inc(BlackHoleTimer);
{ ๋ธ๋ํ ์งํ ์ข
๋ฃ }
if BlackHoleTimer >= BlackHoleDuration then
begin
{ ๋ฒ์คํธ ์์ }
IsBlackHoleActive := False;
IsBurstActive := True;
BlackHoleTimer := 0;
end;
end;
{ ๋ฒ์คํธ ์์ ์ }
if IsBurstActive then
begin
Inc(BlackHoleTimer);
{ ๋ฒ์คํธ ์งํ ์ข
๋ฃ }
if BlackHoleTimer >= BurstDuration then
begin
IsBurstActive := False;
BlackHoleTimer := 0;
RemoveFollowObjects;
end;
end;
end;
{ ๋ธ๋ํ ์ดํํธ ๊ทธ๋ฆฌ๊ธฐ }
procedure TForm1.DrawBlackHoleEffect;
var
EffectRadius: Integer;
begin
if IsBlackHoleActive then
begin
{ ์๊ฐ์ ๋ฐ๋ผ ์ดํํธ ํฌ๊ธฐ ๋ณ๊ฒฝ }
EffectRadius := Round(5 + (BlackHoleTimer / BlackHoleDuration) * 75); // 5 ~ 75
{ ๋ธ๋ํ ๊ทธ๋ฆฌ๊ธฐ }
PaintBox1.Canvas.Pen.Color := clPurple;
PaintBox1.Canvas.Brush.Color := clBlack;
PaintBox1.Canvas.Ellipse(
BlackHoleCenter.X - EffectRadius,
BlackHoleCenter.Y - EffectRadius,
BlackHoleCenter.X + EffectRadius,
BlackHoleCenter.Y + EffectRadius
);
end;
end;
{ ํ๋ก์ ํธ ์์ }
procedure TForm1.FormCreate(Sender: TObject);
begin
{ ๊ฒ์์ ์ฐ์ด๋ ๋ณ์ ์ด๊ธฐํ }
Objects := TList.Create;
GameOver := False;
Score := 1;
ScoreTimer := 0;
Randomize;
{ ๊ฒ์ ํ์ด๋จธ }
Timer1.Interval := 30; // 30ms = ์ฝ 33 FPS
Timer1.Enabled := True;
{ Spawn ํ์ด๋จธ }
TimerSpawn.Interval := 10000; // 10์ด
TimerSpawn.Enabled := True;
{ ๋ธ๋ํ ๋ฐ ํญ๋ฐ ๊ด๋ จ ๋ณ์ ์ด๊ธฐํ }
IsBlackHoleActive := False;
IsBurstActive := False;
BlackHoleTimer := 0;
{ ๋ธ๋ํ ๋ฐ ๋ฒ์คํธ ํจ๊ณผ }
BlackHoleDuration := Round(2000 / Timer1.Interval); // 2์ด
BurstDuration := Round(1000 / Timer1.Interval); // 1์ด
{ ๋ธ๋ํ ์์ฑ ์๊ฐ (25์ด๋ง๋ค) }
BlackHoleSpawnInterval := Round(25000 / Timer1.Interval);
BlackHoleSpawnTimer := 0;
{ ์๋์ฐ ์ค์ }
WindowState := wsMaximized; // ์ ์ฒดํ๋ฉด
Cursor := crNone; // ๋ง์ฐ์ค ์ปค์ ์จ๊น
PaintBox1.Cursor := crNone; // PaintBox์์๋ ์ปค์ ์จ๊น
DoubleBuffered := True; // ๊น๋นก์ ๋ฐฉ์ง
{ ๋ง์ฐ์ค ์ค๋ธ์ ํธ ์์ฑ }
MouseFollower := TObjMouse.Create;
Objects.Add(MouseFollower);
{ ์ค๋ธ์ ํธ ์์ฑ }
CreateRandomObject;
end;
{ ํ๋ก์ ํธ ์ข
๋ฃ ์ }
procedure TForm1.FormDestroy(Sender: TObject);
var
i: Integer;
begin
{ List ํด์ }
if Assigned(Objects) then
begin
for i := 0 to Objects.Count - 1 do
TObject(Objects[i]).Free;
Objects.Free;
end;
end;
{ ๋ง์ฐ์ค๋ฅผ ์์ง์ผ ๋๋ง๋ค }
procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
{ ๋ง์ฐ์ค ์ค๋ธ์ ํธ ์์น ์ด๊ธฐํ }
if Assigned(MouseFollower) then
MouseFollower.SetPosition(X, Y);
end;
{ Spawn ํ์ด๋จธ }
procedure TForm1.TimerSpawnTimer(Sender: TObject);
begin
if not GameOver then
begin
CreateRandomObject;
CreateFollowObject;
end;
end;
{ ํ์ด๋จธ ์ด๋ฒคํธ }
procedure TForm1.Timer1Timer(Sender: TObject);
var
i, j: Integer;
obj: TBaseObject;
obj1, obj2: TBaseObject;
begin
if Objects = nil then Exit;
if GameOver then Exit;
{ ์ ์ ์
๋ฐ์ดํธ }
UpdateScore;
{ ๋ธ๋ํ ๋ฐ๋ }
Inc(BlackHoleSpawnTimer);
if (not IsBlackHoleActive) and (BlackHoleSpawnTimer >= BlackHoleSpawnInterval) then
begin
{ ํ๋ฉด ์ค์์ ๋ธ๋ํ ์์ฑ }
ActivateBlackHole(Point(Panel1.Width div 2, Panel1.Height div 2));
BlackHoleSpawnTimer := 0;
end;
{ ๋ธ๋ํ ์ดํํธ ๋ฐ๋ }
UpdateBlackHoleEffect;
{ ๋ฐฐ๊ฒฝ ์ด๊ธฐํ }
PaintBox1.Canvas.Brush.Color := clBlack;
PaintBox1.Canvas.FillRect(Rect(0, 0, Panel1.Width, Panel1.Height));
{ ํ๋ฉด์ ์๋ ๋ชจ๋ ์ค๋ธ์ ํธ ์ด๋ }
for i := 0 to Objects.Count - 1 do
begin
obj := TBaseObject(Objects[i]);
obj.Move; // TBaseObject.Move์์ ๋ธ๋ํ/๋ฒ์คํธ ๋ก์ง์ ์ฒ๋ฆฌ
end;
// ์ฃฝ์ ์ค๋ธ์ ํธ ์ญ์ ์ฒ๋ฆฌ: ์ญ์์ผ๋ก ์ํํ๋ฉฐ IsDead๊ฐ True์ธ ๊ฐ์ฒด ์ญ์
for i := Objects.Count - 1 downto 0 do
begin
obj := TBaseObject(Objects[i]);
if obj.IsDead then
begin
Objects.Delete(i);
obj.Free;
end;
end;
{ ๋ง์ฐ์ค ์ค๋ธ์ ํธ๋ฅผ ์ ์ธํ ๋ค๋ฅธ ์ค๋ธ์ ํธ๋ผ๋ฆฌ์ ์ถฉ๋ }
if not (IsBlackHoleActive or IsBurstActive) then
begin
for i := 0 to Objects.Count - 2 do
begin
for j := i + 1 to Objects.Count - 1 do
begin
Obj1 := TBaseObject(Objects[i]);
Obj2 := TBaseObject(Objects[j]);
// ObjD, ObjFollow, ObjMouse๋ ์ถฉ๋ ๋ฌด์
if (Obj1.ObjType = ObjD) or (Obj2.ObjType = ObjD) or
(Obj1.ObjType = ObjFollow) or (Obj2.ObjType = ObjFollow) or
(Obj1.ObjType = ObjMouse) or (Obj2.ObjType = ObjMouse) then
Continue;
{ ์ถฉ๋ํ ์ค๋ธ์ ํธ๋ง ์ ํ (ObjA, ObjB, ObjC ๊ฐ์ ์ถฉ๋๋ง) }
if CheckCollision(Obj1, Obj2) then
begin
{ ์์ชฝ ๋ชจ๋ ํ์ }
Obj1.SpeedX := -Obj1.SpeedX;
Obj1.SpeedY := -Obj1.SpeedY;
Obj2.SpeedX := -Obj2.SpeedX;
Obj2.SpeedY := -Obj2.SpeedY;
{ ์๋ก๋ฅผ ์ด์ง์ ๋ฐ์ด์ ๊ฒน์น๋ ์ํฉ ๋ฐฉ์ง }
Obj1.X := Obj1.X + Obj1.SpeedX;
Obj1.Y := Obj1.Y + Obj1.SpeedY;
Obj2.X := Obj2.X + Obj2.SpeedX;
Obj2.Y := Obj2.Y + Obj2.SpeedY;
end;
end;
end;
end;
{ ๋ง์ฐ์ค ์ค๋ธ์ ํธ์ ๋ค๋ฅธ ์ค๋ธ์ ํธ๋ค ๊ฐ์ ์ถฉ๋ ์ฒ๋ฆฌ (ObjD, ObjFollow ํฌํจ) }
if Assigned(MouseFollower) then
begin
for i := 0 to Objects.Count - 1 do
begin
obj := TBaseObject(Objects[i]);
if (obj.ObjType <> ObjMouse) then
begin
if CheckCollision(MouseFollower, obj) then
begin
GameOver := True;
Timer1.Enabled := False;
TimerSpawn.Enabled := False;
ShowMessage('๊ฒ์ ์ค๋ฒ!' + sLineBreak + '์ต์ข
์ ์: ' + IntToStr(Score) + sLineBreak + '๋ค์ ์์ํ๋ ค๋ฉด ํ์ธ์ ๋๋ฅด์ธ์.');
ResetGame;
Exit;
end;
end;
end;
end;
{ ํ๋ฉด์ ์กด์ฌํ๋ ๋ชจ๋ ์ค๋ธ์ ํธ ๋์ }
for i := 0 to Objects.Count - 1 do
begin
obj := TBaseObject(Objects[i]);
{ ์ค๋ธ์ ํธ ๋ณ ์์ ์ง์ }
case obj.ObjType of
ObjA: PaintBox1.Canvas.Brush.Color := clRed;
ObjB: PaintBox1.Canvas.Brush.Color := clGreen;
ObjC: PaintBox1.Canvas.Brush.Color := clBlue;
ObjD: PaintBox1.Canvas.Brush.Color := clYellow;
ObjFollow: PaintBox1.Canvas.Brush.Color := clLime; // ObjFollow ์์
ObjMouse: PaintBox1.Canvas.Brush.Color := clWhite; // ๋ง์ฐ์ค ๋ฐ๋ผ์ค๋ ํฐ์ ์ค๋ธ์ ํธ
else
PaintBox1.Canvas.Brush.Color := clBlack;
end;
{ ์ค๋ธ์ ํธ ๊ทธ๋ฆฌ๊ธฐ }
PaintBox1.Canvas.FillRect(Rect(obj.X, obj.Y, obj.X + obj.Width, obj.Y + obj.Height));
end;
{ ๋ธ๋ํ ์ดํํธ ๊ทธ๋ฆฌ๊ธฐ }
DrawBlackHoleEffect;
{ ์ ์ ํ์ }
PaintBox1.Canvas.Font.Color := clWhite;
PaintBox1.Canvas.Font.Size := 20;
PaintBox1.Canvas.Font.Style := [fsBold];
PaintBox1.Canvas.Brush.Style := bsClear; // ํฌ๋ช
๋ฐฐ๊ฒฝ
PaintBox1.Canvas.TextOut(20, 20, '์ ์: ' + IntToStr(Score));
PaintBox1.Canvas.Brush.Style := bsSolid; // ๋ค์ ์ฑ์ฐ๊ธฐ ๋ชจ๋๋ก ๋ณต์
PaintBox1.Canvas.Font.Color := clWhite;
PaintBox1.Canvas.Font.Size := 20;
PaintBox1.Canvas.Font.Style := [fsBold];
PaintBox1.Canvas.Brush.Style := bsClear; // ํฌ๋ช
๋ฐฐ๊ฒฝ
PaintBox1.Canvas.TextOut(20, 50, '์ต๊ณ ์ ์: ' + IntToStr(MaxScore));
PaintBox1.Canvas.Brush.Style := bsSolid; // ๋ค์ ์ฑ์ฐ๊ธฐ ๋ชจ๋๋ก ๋ณต์
end;
end.2
</aside>