unit UGraphicClasses; interface type TParticle = Class X, Y : Real; //Position 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 StarType : Integer; // 1: GoldenNote | 2: PerfectNote Constructor Create(cX,cY: Real; cTex: Cardinal; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : Integer); procedure Draw; 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; PerfNoteArray : Array of PerfectNotePositions; DelayAfterKillall : Integer; constructor Create; procedure Draw; function Spawn(X, Y: Real; Tex: Cardinal; Live: Byte; StartFrame : Integer; RecArrayIndex : Integer; StarType : Integer): 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); end; var GoldenRec : TEffectManager; implementation uses sysutils, Windows,OpenGl12, UThemes, USkins, UGraphic, UDrawTexture, UTexture, math, dialogs; //TParticle Constructor TParticle.Create(cX,cY: Real; cTex: Cardinal; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : Integer); begin X := cX; Y := cY; Tex := cTex; Live := cLive; Frame:= cFrame; RecIndex := cRecArrayIndex; StarType := cStarType; end; procedure TParticle.Draw; var W, H: real; Alpha : real; begin //Fade Eyecandy Case StarType of 1: begin Alpha := (-cos((Frame+1)*2*pi/16)+1); W := 20; H := 20; glColor4f(0.99, 1, 0.6, Alpha); end; 2: begin Alpha := (-cos((Frame+1)*2*pi/16)+1); W := 30; H := 30; glColor4f(1, 1, 0.95, Alpha); end; 3: begin Alpha := (Live/3); W := 15; H := 15; glColor4f(1, 1, 0.9, Alpha); end; end; 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; constructor TEffectManager.Create; begin LastTime := GetTickCount; end; procedure TEffectManager.Draw; var I: Integer; CurrentTime: Cardinal; const DelayBetweenFrames : Integer = 100; begin CurrentTime := GetTickCount; //Manage particle life if (CurrentTime > (LastTime + DelayBetweenFrames)) then begin LastTime := CurrentTime; for I := 0 to high(Particle) do begin Particle[I].Frame := (Particle[I].Frame + 1 ) mod 16; //Live = 0 => Live forever if (Particle[I].Live > 0) then begin Dec(Particle[I].Live); end; end; 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; function TEffectManager.Spawn(X, Y: Real; Tex: Cardinal; Live: Byte; StartFrame : Integer; RecArrayIndex : Integer; StarType : Integer): Cardinal; begin Result := Length(Particle); SetLength(Particle, (Result + 1)); Particle[Result] := TParticle.Create(X, Y, Tex, Live, StartFrame, RecArrayIndex, StarType); end; 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(Xkatze, Ykatze, Tex_Note_Star.TexNum, 16 - RandomFrame, RandomFrame, P, 1); inc(RecArray[P].CurrentStarCount); end; end; draw; end; procedure TEffectManager.Kill(Index: Cardinal); var LastParticleIndex : Cardinal; begin // We put the last element of the array on the place where our element_to_delete resides and then we shorten the array - cool, hu? :P LastParticleIndex := high(Particle); if not(LastParticleIndex = -1) then begin Try Finally if not(Particle[Index].RecIndex = -1) then dec(RecArray[Particle[Index].RecIndex].CurrentStarCount); Particle[Index].Destroy; Particle[Index] := Particle[LastParticleIndex]; SetLength(Particle, LastParticleIndex); end; end; end; procedure TEffectManager.KillAll(); begin //It's the kill all kennies rotuine while Length(Particle) > 0 do Kill(0); SetLength(RecArray,0); SetLength(PerfNoteArray,0); end; procedure TeffectManager.GoldenNoteTwinkle(Top,Bottom,Right: Real); //Twinkle stars while golden note hit var C, P, XKatze, YKatze: Integer; begin DelayAfterKillall:=10; // To be used later, for the screen change issue For P := 0 to high(RecArray) do // Are we inside a GoldenNoteRectangle? begin if ((RecArray[P].xBottom >= Right) and (RecArray[P].xTop <= Right) and (RecArray[P].yTop <= (Top+Bottom)/2) and (RecArray[P].yBottom >= (Top+Bottom)/2)) then begin for C := 1 to 8 do begin Ykatze := RandomRange(ceil(Top) , ceil(Bottom)); XKatze := RandomRange(-7,3); Spawn(Ceil(Right)+XKatze, YKatze, Tex_Note_Star.TexNum, 3, 0, -1, 3); end; exit; // found a 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 if ((ceil(PerfNoteArray[P].xPos) = ceil(Xtop)) and (ceil(PerfNoteArray[P].yPos) = 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(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, Tex_Note_Perfect_Star.TexNum, 16 - RandomFrame, RandomFrame, -1, 2); end; end; end.