Jump to content

Willicious

Members
  • Content Count

    92
  • Joined

  • Last visited

Everything posted by Willicious

  1. The app I'm working on has different "screens", which are each essentially large bitmaps. When closing a screen to go to the next one, the following code provides a fade-to-black transition effect: procedure TGameBaseScreen.FadeOut; var Steps: Cardinal; i: Integer; P: PColor32; StartTickCount: Cardinal; IterationDiff: Integer; RGBDiff: Integer; const TOTAL_STEPS = 32; STEP_DELAY = 12; begin Steps := 0; StartTickCount := GetTickCount; while Steps < TOTAL_STEPS do begin IterationDiff := ((GetTickCount - StartTickCount) div STEP_DELAY) - Steps; if IterationDiff = 0 then Continue; RGBDiff := IterationDiff * 8; with ScreenImg.Bitmap do begin P := PixelPtr[0, 0]; for i := 0 to Width * Height - 1 do begin with TColor32Entry(P^) do begin if R > RGBDiff then Dec(R, RGBDiff) else R := 0; if G > RGBDiff then Dec(G, RGBDiff) else G := 0; if B > RGBDiff then Dec(B, RGBDiff) else B := 0; end; Inc(P); end; end; Inc(Steps, IterationDiff); ScreenImg.Bitmap.Changed; Changed; Update; end; end; Is there any way this same code can be modified to create a new FadeIn; procedure which allows the screen images to fade-in-from-black? I'm guessing I need to first specify that RGB := 0, 0, 0 and then increase the RGB values until they reach the actual bitmap values. Do I first need to "get" those values somehow? Or, is there a better way to achieve the Fade In/Out procedures? (note that we're dealing with combined bitmaps here, rather than single images)
  2. Willicious

    Change "FadeOut" code to "FadeIn" code

    @Anders - Brilliant! This last one worked a treat. I copied in the ShowScreen procedure as an override and it works great for all screens except the play screen (in this case, it fades from white instead of black). However, I also noticed that the latest version of the FadeOut procedure (the one from the PR) also fades to white on the play screen. So, I'm guessing that this is because FadeIn and FadeOut use MasterAlpha, and somewhere in the Lemmix codebase the background of the play screen is set to white, but I could be wrong. I'll look into this more tomorrow. Thanks again, it's taken a long time to get anywhere with this!
  3. Willicious

    Change "FadeOut" code to "FadeIn" code

    OK, I think the reason why none of the attempts at a FadeIn procedure are working is because the UI isn't actually responding to the updates. This could either be because the App is idle at the point the FadeIn is being called, or because it's only processing the first message from the FadeIn procedure, and then none of the others. At one point, I tried displaying an animated "Fade" graphic (basically a large black square which gradually faded to transparent over 8 frames) over the existing screen image - I could only ever get it to display one frame of this animation. The app is definitely capable of processing messages and animations in the menu screens, though, because other animated images (a text scroller) are shown, clickable regions have graphical effects applied to them, and the FadeOut procedure works. Here's where FadeOut is called, maybe there's a clue in here somewhere: procedure TGameBaseScreen.CloseScreen(aNextScreen: TGameScreenType); begin Self.OnKeyDown := nil; Self.OnKeyPress := nil; Self.OnClick := nil; Self.OnMouseDown := nil; Self.OnMouseMove := nil; ScreenImg.OnMouseDown := nil; ScreenImg.OnMouseMove := nil; Application.OnIdle := nil; fScreenIsClosing := True; if fCloseDelay > 0 then begin Update; Sleep(fCloseDelay); end; FadeOut; if GameParams <> nil then begin GameParams.NextScreen := aNextScreen; GameParams.MainForm.Cursor := crNone; end; Close; PostMessage(MainFormHandle, LM_NEXT, 0, 0); end; And, here's where FadeIn is currently being called: constructor TGameBaseMenuScreen.Create(aOwner: TComponent); begin inherited; fKeyStates := TDictionary<Word, UInt64>.Create; fClickableRegions := TObjectList<TClickableRegion>.Create; fMenuFont := TMenuFont.Create; fMenuFont.Load; fBasicCursor := TNLCursor.Create(Min(Screen.Width div 320, Screen.Height div 200) + EXTRA_ZOOM_LEVELS); LoadBasicCursor('amiga.png'); SetBasicCursor; InitializeImage; OnKeyDown := Form_KeyDown; OnKeyUp := Form_KeyUp; OnMouseDown := Form_MouseDown; OnMouseMove := Form_MouseMove; ScreenImg.OnMouseDown := Img_MouseDown; ScreenImg.OnMouseMove := Img_MouseMove; fCalledFromClassicModeButton := False; FadeIn; end;
  4. Willicious

    Change "FadeOut" code to "FadeIn" code

    Thanks again. Made the change, still just getting a black screen. I'll have more time to look over it tomorrow properly, it may be because of where I'm calling the procedure from or something like that.
  5. Willicious

    Change "FadeOut" code to "FadeIn" code

    Thanks for the code snippet Anders, I've given it a quick try and just get a black screen. I'll investigate further later this evening or tomorrow, what you've written looks like it should work. I'll do some debugging and see if I can figure out what's going wrong.
  6. Willicious

    Change "FadeOut" code to "FadeIn" code

    Tried this again today. This yields the same result as always (black screen for 1000ms, then the screenimg.bitmap is drawn at full opacity). I've tried placing "Inc(i)" at various points in the loop, and have also tried using "repeat ... until i = 255" to no avail: procedure TGameBaseScreen.FadeIn; var i: Integer; RemainingTime: Integer; OldRemainingTime: Integer; EndTickCount: Cardinal; const MAX_TIME = 1000; // mS begin EndTickCount := GetTickCount + MAX_TIME; OldRemainingTime := 0; RemainingTime := MAX_TIME; ScreenImg.Bitmap.DrawMode := dmBlend; // So MasterAlpha is used to draw the bitmap while (RemainingTime >= 0) do begin if (RemainingTime <> OldRemainingTime) then begin for i := 0 to 255 do begin ScreenImg.Bitmap.MasterAlpha := i; ScreenImg.Update; end; OldRemainingTime := RemainingTime; end else Sleep(1); RemainingTime := EndTickCount - GetTickCount; Inc(i); end; Application.ProcessMessages; end; For reference, here's the FadeOut procedure as written by Anders, which works perfectly: procedure TGameBaseScreen.FadeOut; var RemainingTime: integer; OldRemainingTime: integer; EndTickCount: Cardinal; const MAX_TIME = 300; // mS begin EndTickCount := GetTickCount + MAX_TIME; OldRemainingTime := 0; RemainingTime := MAX_TIME; ScreenImg.Bitmap.DrawMode := dmBlend; // So MasterAlpha is used to draw the bitmap while (RemainingTime >= 0) do begin if (RemainingTime <> OldRemainingTime) then begin ScreenImg.Bitmap.MasterAlpha := MulDiv(255, RemainingTime, MAX_TIME); ScreenImg.Update; OldRemainingTime := RemainingTime; end else Sleep(1); RemainingTime := EndTickCount - GetTickCount; end; Application.ProcessMessages; end; Any suggestions or comments would be most welcome!
  7. It's in the title. My current CE licence expires tomorrow, and all efforts I've made so far to obtain a new licence have failed. Does anyone know how I can obtain another 1-year licence for this particular edition of RAD (Sydney 10.4.2)? 10.4.2 is the only version that will successfully compile the project I'm working on, and I need to be able to seamlessly continue with it if at all possible. Both 11 and 12 run into problems when getting the project set up, so simply installing the latest version unfortunately isn't the solution. Please help!
  8. I'm a hobbyist and can't justify paying for a Professional version given my limited use of the platform. Also, as stated in the OP, my project only works in 10.4.2 so even if someone were to gift me the latest Pro version, it would be useless to me. Does anyone know of a way to get a new serial for 10.4.2 CE? Anyone had any luck with contacting Embarcadero for help?
  9. Apologies, I didn't explain that properly. I'm not looking for a single point to be true, but rather a number of points along a straight line. So (X = 0), (Y = 0 and 1 and 2 and 3, etc...) would draw the line required. But, the entire line needs to be drawn for the condition to be met. Yes, to be honest I do now remember asking this same question a while back. Here it is. I didn't fully understand the answer given in that topic, but now that I look at it again I can see what's being suggested. It seems that a boolean needs to be set, then each number is iterated over until one returns false (which breaks the loop). If all numbers return true, then we can run the code. That could work, and using "case ... of" could also work, again to set the bool value. Thanks everyone, I'm sure I'll figure it out.
  10. I need to use a full set of numbers as a condition. So, for example, rather than: var i: Integer; for i := 0 to 5 do begin if PosY = Y - i then //whatever end; I need it to be: var i: {not sure what to declare i as}; i := [0..5]; if PoxY := Y - i then begin //whatever end; The code needs to execute iff all conditions are met (Y - 0 and Y - 1 and Y - 2 and Y - 3, etc) and not just if any of the possible 6 conditions are met (Y - 0 or Y - 1 or Y - 2 or Y - 3, etc). I've tried declaring i as "array of Integer;" but get the error "Incompatible types: dynamic array and set". I can't declare it as a set either, so, what do I need to declare i as in order to be able to specify all values between 0 and 5 as the condition?
  11. Willicious

    Profiler for Delphi

    Yes, this is what I'm after. Thanks! 🙂👍
  12. Willicious

    Profiler for Delphi

    Apologies, I appreciate the suggestion and the time you've taken to respond, but this isn't quite what I'm looking for. I need a program that will basically "read" the entire codebase - ideally at source or within the IDE itself - and point out any areas which could be removed, simplified, or optimized to reduce performance bottlenecks. Maybe I'm dreaming and such a thing doesn't exist yet...? I just know that AQTime used to be bundled with RAD Studio but isn't any longer (and, from what I've seen, this does exactly what I'm describing, but is currently mad expensive for someone who only does small open-source projects). Also - I'm looking for somthing that will do the above, and which works straightaway with an absolute minimum of setup. If that doesn't exist, then that's fine. Maybe it will someday 😊
  13. Hi all, I'm looking to find a decent, easy-to-use Profiler to help identify performance bottlenecks and memory leaks. I'm a small-project user so not looking to pay too much - free and open source options are welcome as long as they're straightforward to use - no command line stuff, please. It's 2023 and I'm using RAD Studio 10.4.2 - I believe SmartBear used to provide a standard version of AQTime with an earlier version of RAD, shame they stopped doing this really because now it seems we have to pay big bucks for this particular profiling system. Recommendations and suggestions welcome, thank you!
  14. Willicious

    Profiler for Delphi

    I take it VTune is the Profiler... what is the MAP2PDB for? Complete beginner here, I've been advised to Profile my project's codebase to look for permance issues. Not sure where to start. Also, isn't VTune an expensive Intel app? Ideally looking for free, or inexpensive alternatives. VTune installer says it can integrate with MS Visual Studio, but not RAD Studio - is this even a Delphi app?
  15. Willicious

    [Delphi] Looking for a Delphi Profiler in 2023

    Thanks! I've replied in-topic in case anyone's watching the topic and has any suggestions.
  16. Willicious

    Profiler for Delphi

    Replying again because I forgot to check "notify me of replies", and the site doesn't provide a way to do this after replying
  17. Willicious

    Profiler for Delphi

    Hi, looking for a profiler in 2023. I'm a small-project user and so don't really want to pay. I use RAD Studio 10.4.2, any suggestions?
  18. EDIT: Apologies for the rant-like nature of this post, but... I'm getting frustrated with Delphi programming. Rather than toss my laptop out the window, I'd rather express my frustration here on the Forums and hopefully it comes to something a bit more productive than a broken laptop and a feeling of regret. ----- Why can I sometimes access properties, functions, variables etc from other units, and sometimes not? "Private" and "public" doesn't seem to make any difference, either. Sometimes I'll start to type the name of a class, followed by "." and a list of all the available items comes up. I assure you, sometimes even when I make something "public", it still won't appear in that list. Why??? Also, the practice of creating "instances" of classes within procedures is ridiclously cumbersome and unintuitive. If I've created a property/variable/field/whatever in Class1.pas, it should be accessible from Class2.pas without me having to create a "version" of Class1 first. If it's declared in uses, that should be that! Forgive me for the rant, but aren't we as programmers supposed to be in charge of the program, not the other way around?!
  19. Willicious

    Problems with Delphi class structure / visibility

    Right on the money! GameParams is the global instance, that provides the address from which I can then access Renderer, Theme, and LemNames! And, it works!!! It's reassuring to know that sometimes the only way to know something is to know what to search for. And, thanks to your explanation, I actually understand what's going on here 👍
  20. Willicious

    Problems with Delphi class structure / visibility

    Yes, you're right! There is one called simply fTheme, which is declared and created in LemRendering. This would make sense, since the renderer does all of the drawing/animation work, and for that it needs the sprite types and theme colours. Problem is, I'm having the same issue trying to access LemRendering from GamePreviewScreen. To be more specific, the class in LemRendering is called TRenderer, and here's where the instance of TNeoTheme is created: constructor TRenderer.Create; begin inherited Create; fTheme := TNeoTheme.Create; LemRendering is in the uses clause at the very top of GamePreviewScreen, not the implementation/uses clause. Thanks for your detailed replies btw, very helpful 🙂👍 I'm closer to understanding the principle, but there are still times like I described in the video where I do declare an instance, but it's empty - like if one of the table builders in your example hadn't read the instructions. And, in the example here, I've managed to find an existing instance of TNeoTheme which is an actual "table builder", but I now need to know how to direct them to GamePreviewScreen to do some stuff over there. Or... don't I? Is this one of those times when declaring a new instance in GamePreviewScreen would be creating a new "table builder who has read the instructions"?
  21. Willicious

    Problems with Delphi class structure / visibility

    OK, here's a video demonstrating the issue I'm having. It comes up time and again, and sometimes I can find a fix by mimicking code elsewhere in the project. But, I'd much rather understand exactly what's going on for those times when there's nothing to mimic, and I need to fix it myself. Apologies again for the tone of the OP in this topic, I have been very frustrated with it recently and I would appreciate whatever help you can offer. I do want to try and understand as much as I can, and I realise that Delphi itself isn't the problem!
  22. Willicious

    Problems with Delphi class structure / visibility

    It happened again today when I was briefly attempting to use a property of (LemTheme unit / TTheme class) in (GamePreviewScreen Unit). The problem is that LemTheme / TTheme cannot be called as a separate instance because the original instance itself loads a particular theme for use in many different parts of the game (but unfortunately not the Preview screen). If I create a new instance of TTheme in the Preview screen logic, it will be an empty instance. The actual instance where all the stuff gets loaded is in LemTheme, in the actual TTheme class itself. This was essentially the problem I was having yesterday: I was attempting to use a new instance of TReplay, but all the actual replay data was being created and stored in a different instance (the original one, in the LemReplay unit). To use one of the analogies given here... I need to use some of the furniture in house 2 whilst I'm in house 1, but to do so is impossible without copying the furniture. As I understand it, it's bad practice to write code again that's already written somewhere else (i.e. I shouldn't have to load the Replay or the Theme again in the current Unit/Class if it's already been loaded in another Unit/Class). Instead, I should be able to access that data, but... sometimes, it just doesn't let me do so, and I'm not entirely sure why. Maybe I can make a quick video sometime demonstrating the problem. Copying and pasting code can lead to confusion, sidetracking and over-focus on context rather than getting to the actual root of the problem (which, in my case, is that I'm clearly not understanding the basic principles of OOP).
  23. Willicious

    Problems with Delphi class structure / visibility

    For what it's worth, I've managed to find a solution to the particular problem that's been bothering me today. The answer was in the existing code, I just needed to find the correct function, and the correct way to call it in another unit. However, any advice on calling properties/functions/procedures/fields/etc from another class/unit would be invaluable. I'm willing to learn! Thanks for your patience, everyone. Apologies again for the outpouring of frustration.
  24. Willicious

    Problems with Delphi class structure / visibility

    LemGame is a different unit, it contains a (variable? property? field?) called CurrentIteration which, essentially, represents the current in-game frame.
  25. Willicious

    Problems with Delphi class structure / visibility

    Basically, everything I try (and fail) to do comes down to undeclared identifiers, not being able to call procedures/functions/properties/variables from other classes. It's always the thing that holds me back. All the ideas are there, and should work. Here's an example: function TReplay.GetRRChangeOnCurrentFrame: Boolean; var i: Integer; begin Result := False; for i := 0 to fSpawnIntervalChanges.Count -1 do begin if TReplayChangeSpawnInterval(fSpawnIntervalChanges[i]).Frame = LemGame.CurrentIteration then begin Result := True; OutputDebugString(PChar('SpawnIntervalChangeDetected')); Exit; end; end; end; In this code, the call for LemGame.CurrentIteration generates an undeclared identifier error. This is in spite of LemGame being one of the uses in this unit, and CurrentIteration being public and callable from other units (elsewhere, it's called as Game.CurrentIteration, but that doesn't work here either). All I want to do is return this value to True if the Spawn Interval has changed on the current frame. All the code is there, the ideas work in theory, but for some reason I just..... can't use this bit of the code in this particular place!
×