unit UGraphicClasses;
interface
const DelayBetweenFrames : Cardinal = 100;
type
TParticleType=(GoldenNote, PerfectNote, NoteHitTwinkle, PerfectLineTwinkle);
TColour3f = Record
r, g, b: Real;
end;
TParticle = Class
X, Y : Real; //Position
W, H : Cardinal; //dimensions of particle
Col : TColour3f; // Colour of particle
Frame : Byte; //act. Frame
Tex : Cardinal; //Tex num from Textur Manager
Live : Byte; //How many Cycles before Kill
RecIndex : Integer; //To which rectangle this particle belongs (only GoldenNote)
StarType : TParticleType; // GoldenNote | PerfectNote | NoteHitTwinkle | PerfectLineTwinkle
Alpha : Real; // used for fading...
mX, mY : Real; // movement-vector for PerfectLineTwinkle
Constructor Create(cX,cY: Real; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : TParticleType; Player: Cardinal);
procedure Draw;
procedure LiveOn;
end;
RectanglePositions = Record
xTop, yTop, xBottom, yBottom : Real;
TotalStarCount : Integer;
CurrentStarCount : Integer;
end;
PerfectNotePositions = Record
xPos, yPos : Real;
end;
TEffectManager = Class
Particle : array of TParticle;
LastTime : Cardinal;
RecArray : Array of RectanglePositions;
TwinkleArray : Array[0..5] of Real; // store x-position of last twinkle for every player
PerfNoteArray : Array of PerfectNotePositions;
constructor Create;
destructor Destroy; override;
procedure Draw;
function Spawn(X, Y: Real;
Live: Byte;
StartFrame: Integer;
RecArrayIndex: Integer; // this is only used with GoldenNotes
StarType: TParticleType;
Player: Cardinal // for PerfectLineTwinkle
): Cardinal;
procedure SpawnRec();
procedure Kill(index: Cardinal);
procedure KillAll();
procedure SaveGoldenStarsRec(Xtop, Ytop, Xbottom, Ybottom: Real);
procedure SavePerfectNotePos(Xtop, Ytop: Real);
procedure GoldenNoteTwinkle(Top,Bottom,Right: Real; Player: Integer);
end;
var GoldenRec : TEffectManager;
implementation
uses sysutils, Windows,OpenGl12, UThemes, USkins, UGraphic, UDrawTexture, UTexture, math, dialogs;
//TParticle
Constructor TParticle.Create(cX,cY: Real; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : TParticleType; Player: Cardinal);
begin
inherited Create;
X := cX;
Y := cY;
Live := cLive;
Frame:= cFrame;
RecIndex := cRecArrayIndex;
StarType := cStarType;
Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
case cStarType of
GoldenNote:
begin
Tex := Tex_Note_Star.TexNum;
W := 20;
H := 20;
Col.r := 0.99;
Col.g := 1;
Col.b := 0.6;
end;
PerfectNote:
begin
Tex := Tex_Note_Perfect_Star.TexNum;
W := 30;
H := 30;
Col.r := 1;
Col.g := 1;
Col.b := 0.95;
end;
NoteHitTwinkle:
begin
Tex := Tex_Note_Star.TexNum;
Alpha := (Live/10); // linear fade-out
W := 15;
H := 15;
Col.r := 1;
Col.g := 1;
Col.b := RandomRange(10*Live,100)/80; //0.9;
end;
PerfectLineTwinkle:
begin
Tex := Tex_Note_Star.TexNum;
W := RandomRange(10,30);
H := W;
// hier muss entsprechend des players farbe gesetzt werden (sollten wir dann auch �bergeben bekommen)
// case Player of
// ...
Col.r := 1;
Col.g := 0.5;
Col.b := 0.5;
mX := RandomRange(-5,5);
mY := RandomRange(-5,5);
end;
else // just some random default values
begin
Tex := Tex_Note_Star.TexNum;
Alpha := 1;
W := 20;
H := 20;
Col.r := 1;
Col.g := 1;
Col.b := 1;
end;
end;
end;
procedure TParticle.LiveOn;
begin
//Live = 0 => Live forever <blindy> ?? die werden doch aber im Manager bei Draw get�tet, wenns 0 is
if (Live > 0) then
Dec(Live);
// animate frames
Frame := ( Frame + 1 ) mod 16;
// make our particles do funny stuff (besides being animated)
case StarType of
GoldenNote:
begin
Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
end;
PerfectNote:
begin
Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
end;
NoteHitTwinkle:
begin
Alpha := (Live/10); // linear fade-out
end;
PerfectLineTwinkle:
begin
Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
// move around
X := X + mX;
Y := Y + mY;
end;
end;
end;
procedure TParticle.Draw;
begin
glColor4f(Col.r, Col.g, Col.b, Alpha);
glBindTexture(GL_TEXTURE_2D, Tex);
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
begin
glBegin(GL_QUADS);
glTexCoord2f((1/16) * Frame, 0); glVertex2f(X-W, Y-H);
glTexCoord2f((1/16) * Frame + (1/16), 0); glVertex2f(X-W, Y+H);
glTexCoord2f((1/16) * Frame + (1/16), 1); glVertex2f(X+W, Y+H);
glTexCoord2f((1/16) * Frame, 1); glVertex2f(X+W, Y-H);
glEnd;
end;
glcolor4f(1,1,1,1);
end;
// end of TParticle
// TEffectManager
constructor TEffectManager.Create;
var c: Cardinal;
begin
inherited;
LastTime := GetTickCount;
for c:=0 to 5 do
begin
TwinkleArray[c] := 0;
end;
end;
destructor TEffectManager.Destroy;
begin
Killall;
inherited;
end;
procedure TEffectManager.Draw;
var
I: Integer;
CurrentTime: Cardinal;
//const
// DelayBetweenFrames : Cardinal = 100;
begin
CurrentTime := GetTickCount;
//Manage particle life
if (CurrentTime - LastTime) > DelayBetweenFrames then
begin
LastTime := CurrentTime;
for I := 0 to high(Particle) do
Particle[I].LiveOn;
end;
I := 0;
//Kill dead particles
while (I <= High(Particle)) do
begin
if (Particle[I].Live <= 0) then
begin
kill(I);
end
else
begin
inc(I);
end;
end;
//Draw
for I := 0 to high(Particle) do
begin
Particle[I].Draw;
end;
end;
// this method creates just one particle
function TEffectManager.Spawn(X, Y: Real; Live: Byte; StartFrame : Integer; RecArrayIndex : Integer; StarType : TParticleType; Player: Cardinal): Cardinal;
begin
Result := Length(Particle);
SetLength(Particle, (Result + 1));
Particle[Result] := TParticle.Create(X, Y, Live, StartFrame, RecArrayIndex, StarType, Player);
end;
// manage Sparkling of GoldenNote Bars
procedure TEffectManager.SpawnRec();
Var
Xkatze, Ykatze : Real;
RandomFrame : Integer;
P : Integer; // P as seen on TV as Positionman
begin
//Spawn a random amount of stars within the given coordinates
//RandomRange(0,14) <- this one starts at a random frame, 16 is our last frame - would be senseless to start a particle with 16, cause it would be dead at the next frame
for P:= 0 to high(RecArray) do
begin
while (RecArray[P].TotalStarCount > RecArray[P].CurrentStarCount) do
begin
Xkatze := RandomRange(Ceil(RecArray[P].xTop), Ceil(RecArray[P].xBottom));
Ykatze := RandomRange(Ceil(RecArray[P].yTop), Ceil(RecArray[P].yBottom));
RandomFrame := RandomRange(0,14);
// Spawn a GoldenNote Particle
Spawn(Xkatze, Ykatze, 16 - RandomFrame, RandomFrame, P, GoldenNote, 0);
inc(RecArray[P].CurrentStarCount);
end;
end;
draw;
end;
// kill one particle (with given index in our particle array)
procedure TEffectManager.Kill(Index: Cardinal);
var
LastParticleIndex : Integer;
begin
// delete particle indexed by Index,
// overwrite it's place in our particle-array with the particle stored at the last array index,
// shorten array
LastParticleIndex := high(Particle);
if not(LastParticleIndex = -1) then // is there still a particle to delete?
begin
if not(Particle[Index].RecIndex = -1) then // if it is a GoldenNote particle...
dec(RecArray[Particle[Index].RecIndex].CurrentStarCount); // take care of its associated GoldenRec
// now get rid of that particle
Particle[Index].Destroy;
Particle[Index] := Particle[LastParticleIndex];
SetLength(Particle, LastParticleIndex);
end;
end;
// clean up all particles and management structures
procedure TEffectManager.KillAll();
var c: Cardinal;
begin
//It's the kill all kennies rotuine
while Length(Particle) > 0 do // kill all existing particles
Kill(0);
SetLength(RecArray,0); // remove GoldenRec positions
SetLength(PerfNoteArray,0); // remove PerfectNote positions
for c:=0 to 5 do
begin
TwinkleArray[c] := 0; // reset GoldenNoteHit memory
end;
end;
procedure TeffectManager.GoldenNoteTwinkle(Top,Bottom,Right: Real; Player: Integer);
//Twinkle stars while golden note hit
// this is called from UDraw.pas, SingDrawPlayerCzesc
var
C, P, XKatze, YKatze, LKatze: Integer;
H: Real;
begin
// make sure we spawn only one time at one position
if (TwinkleArray[Player] < Right) then
For P := 0 to high(RecArray) do // Are we inside a GoldenNoteRectangle?
begin
H := (Top+Bottom)/2; // helper...
with RecArray[P] do
if ((xBottom >= Right) and (xTop <= Right) and
(yTop <= H) and (yBottom >= H)) then
begin
TwinkleArray[Player] := Right; // remember twinkle position for this player
for C := 1 to 20 do
begin
Ykatze := RandomRange(ceil(Top) , ceil(Bottom));
XKatze := RandomRange(-7,3);
LKatze := RandomRange(4,10);
Spawn(Ceil(Right)+XKatze, YKatze, LKatze, 0, -1, NoteHitTwinkle, 0);
end;
for C := 1 to 5 do
begin
Ykatze := RandomRange(ceil(Top)-6 , ceil(Top));
XKatze := RandomRange(-5,1);
LKatze := RandomRange(2,3);
Spawn(Ceil(Right)+XKatze, YKatze, LKatze, 0, -1, NoteHitTwinkle, 0);
end;
for C := 1 to 5 do
begin
Ykatze := RandomRange(ceil(Bottom), ceil(Bottom)+6);
XKatze := RandomRange(-5,1);
LKatze := RandomRange(2,3);
Spawn(Ceil(Right)+XKatze, YKatze, LKatze, 0, -1, NoteHitTwinkle, 0);
end;
for C := 1 to 3 do
begin
Ykatze := RandomRange(ceil(Top)-10 , ceil(Top)-6);
XKatze := RandomRange(-5,1);
LKatze := RandomRange(1,2);
Spawn(Ceil(Right)+XKatze, YKatze, LKatze, 0, -1, NoteHitTwinkle, 0);
end;
for C := 1 to 3 do
begin
Ykatze := RandomRange(ceil(Bottom)+6 , ceil(Bottom)+10);
XKatze := RandomRange(-5,1);
LKatze := RandomRange(1,2);
Spawn(Ceil(Right)+XKatze, YKatze, LKatze, 0, -1, NoteHitTwinkle, 0);
end;
exit; // found a matching GoldenRec, did spawning stuff... done
end;
end;
end;
procedure TEffectManager.SaveGoldenStarsRec(Xtop, Ytop, Xbottom, Ybottom: Real);
var
P : Integer; // P like used in Positions
NewIndex : Integer;
begin
For P := 0 to high(RecArray) do // Do we already have that "new" position?
begin
if ((ceil(RecArray[P].xTop) = ceil(Xtop)) and (ceil(RecArray[P].yTop) = ceil(Ytop))) then
exit; // it's already in the array, so we don't have to create a new one
end;
// we got a new position, add the new positions to our array
NewIndex := Length(RecArray);
SetLength(RecArray, NewIndex + 1);
RecArray[NewIndex].xTop := Xtop;
RecArray[NewIndex].yTop := Ytop;
RecArray[NewIndex].xBottom := Xbottom;
RecArray[NewIndex].yBottom := Ybottom;
RecArray[NewIndex].TotalStarCount := ceil(Xbottom - Xtop) div 12 + 3;
RecArray[NewIndex].CurrentStarCount := 0;
end;
procedure TEffectManager.SavePerfectNotePos(Xtop, Ytop: Real);
var
P : Integer; // P like used in Positions
NewIndex : Integer;
RandomFrame : Integer;
Xkatze, Ykatze : Integer;
begin
For P := 0 to high(PerfNoteArray) do // Do we already have that "new" position?
begin
with PerfNoteArray[P] do
if ((ceil(xPos) = ceil(Xtop)) and (ceil(yPos) = ceil(Ytop))) then
exit; // it's already in the array, so we don't have to create a new one
end; //for
// we got a new position, add the new positions to our array
NewIndex := Length(PerfNoteArray);
SetLength(PerfNoteArray, NewIndex + 1);
PerfNoteArray[NewIndex].xPos := Xtop;
PerfNoteArray[NewIndex].yPos := Ytop;
for P:= 0 to 2 do
begin
Xkatze := RandomRange(ceil(Xtop) - 5 , ceil(Xtop) + 10);
Ykatze := RandomRange(ceil(Ytop) - 5 , ceil(Ytop) + 10);
RandomFrame := RandomRange(0,14);
Spawn(Xkatze, Ykatze, 16 - RandomFrame, RandomFrame, -1, PerfectNote, 0);
end; //for
end;
end.