Recent

Author Topic: Castle Game Engine (Cross Platform) - Need Help with Drawing a Raycast Vector  (Read 15875 times)

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
But my point was that the initial example didn't need AvatarTransform/UnlitMeshParent created at all in any of the code like that, and the object could be used directly and it would work perfectly - why should that suddenly change?

It doesn't make sense for 1 + 1 to be 2 sometimes and 3 other times, code should always be consistent if you're using the same code, even if you're using different names for objects and variables and such.

michalis

  • Full Member
  • ***
  • Posts: 143
    • Castle Game Engine
But my point was that the initial example didn't need AvatarTransform/UnlitMeshParent created at all in any of the code like that, and the object could be used directly and it would work perfectly - why should that suddenly change?

It doesn't make sense for 1 + 1 to be 2 sometimes and 3 other times, code should always be consistent if you're using the same code, even if you're using different names for objects and variables and such.

There's a number of differences between what example ( https://github.com/castle-engine/castle-engine/blob/master/examples/research_special_rendering_methods/test_rendering_opengl_capabilities/ ) does and what your code is doing. E.g. your code adds a field to TMyMesh, and you didn't initialize this field.

Really everything is logical and 1+1 is always 2.  But arguing with the compiler as you do, writing that "things don't make sense", writing "facepalm" etc., doesn't get you closer to solve the problem. To solve the problem, follow what I now wrote 3 times:  set the "AvatarTransform" field of the "TMyMesh" instance. And follow the error messages you get -- they point to lines in your source code where things are wrong. Investigate what is wrong there.


JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Oh... it makes more sense when I look at the platformer game example for inspiration and it suggests that TBullet must be declared as a class and created with a constructor as one before being used as an input in the code of functions elsewhere, like in GameEnemy.pas for enemy behavior, in order to actually use the bullet correctly; is this what I was supposed to learn on my own?

Or is it perhaps the problem is that PlayerTransform doesn't match the given name of AvatarTransform, and that wasn't something I was supposed to change, again given the example says "Bullet" verbatim in the function that uses it, and not "Bulle" or anything not "Bullet" with all the characters intact?

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Okay, changing the name to be consistent with the actual AvatarTransform doesn't solve the crashing at all; it's still the same error about "access violation at line 61 in CreateMesh" even though I set up the AvatarTransform reference in both gamemymesh.pas and gameviewplay.pas; do you think then that the answer is to set it up as a class, complete with a constructor function and everything, given that it has properties inside it, like the player's models and collider?

michalis

  • Full Member
  • ***
  • Posts: 143
    • Castle Game Engine
Okay, changing the name to be consistent with the actual AvatarTransform doesn't solve the crashing at all; it's still the same error about "access violation at line 61 in CreateMesh" even though I set up the AvatarTransform reference in both gamemymesh.pas and gameviewplay.pas; do you think then that the answer is to set it up as a class, complete with a constructor function and everything, given that it has properties inside it, like the player's models and collider?

Above paragraph is full of confusion. You are doing random things. This will not lead to solution.

What you have to do is: Initialize the field "AvatarTransform" of the instance of class "TMyMesh". It is not initialized now. If it is unclear to you what this sentence means, please consult the Pascal learning resources ( https://castle-engine.io/learn_pascal ).

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
I want to do that, but need help understanding how to actually initialize it, given that when I tried initializing a certain value to it earlier I was told that I was using a duplicate identifer.

Is the key maybe not using a class unless necessary, but just assigning a value to it like any old variable before using it, like assigning the AvatarTransform in the function to be equal to the AvatarTransform from the scene itself?

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Cause again, using the official example from the platformer, that makes a lot of sense too: in the function in GameEnemy.pas that uses references to the Bullet object inside it, you had to assign the bullet a value before you could use it, same deal here with the AvatarTransform. That's the lesson I should have learned I believe;

That variables as custom arguments in a procedure need to always be defined before they are mentioned/called, just like variables in general, whether in a procedure or not.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Okay, so I tried initializing a particular value to it in the function body itself, but because it used the "const" keyword at first it wouldn't accept me trying to initialize a value,

so then I tried assigning a value to it before the procedure ever happened earlier in the code, but that gave me errors about "AvatarTransform is a duplicate identifier",

so I then decided that the "const" keyword is probably unecessary given how the original example I am using didn't have any inputs in that particular function, as we talked about earlier, so I just decided to omit the const keyword to initialize it in the procedure I want directly.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
This is my code as of right now:

Code: Pascal  [Select][+][-]
  1. {
  2.   Copyright 2023-2023 Michalis Kamburelis.
  3.  
  4.   This file is part of "Castle Game Engine".
  5.  
  6.   "Castle Game Engine" is free software; see the file COPYING.txt,
  7.   included in this distribution, for details about the copyright.
  8.  
  9.   "Castle Game Engine" is distributed in the hope that it will be useful,
  10.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12.  
  13.   ----------------------------------------------------------------------------
  14. }
  15.  
  16. { TCastleTransform descendant that renders unlit mesh using TCastleRenderUnlitMesh. }
  17. unit GameMyMesh;
  18.  
  19. interface
  20.  
  21. uses SysUtils,
  22.   CastleRenderPrimitives, CastleBoxes, CastleTransform;
  23.  
  24. type
  25.   { Mesh rendered using TCastleRenderUnlitMesh, not using TCastleScene.
  26.     This is not generally advised, TCastleScene has much more features
  27.     and is easier to use than TCastleRenderUnlitMesh.
  28.     We do this only to test TCastleRenderUnlitMesh with rcForceFixedFunction here. }
  29.   TMyMesh = class(TCastleTransform)
  30.   published
  31.     AvatarTransform: TCastleTransform;
  32.   strict private
  33.     Mesh: TCastleRenderUnlitMesh;
  34.   public
  35.     procedure LocalRender(const Params: TRenderParams); override;
  36.     procedure GLContextClose; override;
  37.     function LocalBoundingBox: TBox3D; override;
  38.   end;
  39.  
  40. implementation
  41.  
  42. uses CastleVectors, CastleRenderContext, CastleColors, CastleGLUtils, GameViewPlay;
  43.  
  44. { TMyMesh -------------------------------------------------------------------- }
  45.  
  46. function TMyMesh.LocalBoundingBox: TBox3D;
  47. begin
  48.   Result := inherited;
  49.   Result := Result + Box3D(
  50.     Vector3(-1, -1, -1),
  51.     Vector3( 1,  1,  1)
  52.   );
  53. end;
  54.  
  55. procedure TMyMesh.LocalRender(const Params: TRenderParams);
  56.  
  57. begin
  58.  
  59.   procedure CreateMesh(AvatarTransform: TCastleTransform);
  60.   var
  61.     PlayerAvatarTransform: TCastleTransform;
  62.   begin
  63.     PlayerAvatarTransform := AvatarTransform;
  64.     Mesh := TCastleRenderUnlitMesh.Create(true);
  65.     Mesh.SetVertexes([
  66.       Vector4(0.0, AvatarTransform.Translation.Y, 0.0, 1.0),
  67.       Vector4(0.0, (AvatarTransform.Translation.Y - AvatarTransform.Direction.Y), 0.0, 1.0)
  68.     ], false);
  69.     Mesh.SetIndexes([
  70.       // line loop on Z = -1
  71.       0, 1
  72.     ]);
  73.     Mesh.Color := Yellow;
  74.   end;
  75.  
  76. var
  77.   SavedDepthTest: Boolean;
  78.   SavedLineWidth: Single;
  79. begin
  80.   inherited;
  81.   SavedDepthTest := RenderContext.DepthTest;
  82.   SavedLineWidth := RenderContext.LineWidth;
  83.   RenderContext.DepthTest := true;
  84.   RenderContext.LineWidth := 5;
  85.  
  86.   if Mesh = nil then
  87.     CreateMesh(AvatarTransform);
  88.   Mesh.ModelViewProjection := RenderContext.ProjectionMatrix *
  89.     Params.RenderingCamera.CurrentMatrix * WorldTransform;
  90.   Mesh.Render(pmLines);
  91.  
  92.   RenderContext.DepthTest := SavedDepthTest;
  93.   RenderContext.LineWidth := SavedLineWidth;
  94. end;
  95.  
  96. procedure TMyMesh.GLContextClose;
  97. begin
  98.   FreeAndNil(Mesh);
  99.   inherited;
  100. end;
  101.  
  102. end.

Unfortunately, I get an error about line 59, 3, where I defined the procedure I want for creating a mesh with custom inputs, is an illegal expression even though I am simply following the formatting of how I should normally declare a procedure, which you can see for yourself is objectively true by looking at 55 close by in particular, which is another procedure with custom inputs.

Is the problem that CreateMesh is hard coded, unlike what I initially thought, and cannot accept custom arguments?

If so, that really stinks because I want to control the raycast coordinates precisely using the player's actual location and not just two arbitrary, nonmoving points like the original example; does anyone know what the best solution is if CreateMesh doesn't actually accept custom arguments?

Josh

  • Hero Member
  • *****
  • Posts: 1361
procedure/functions that are local to a procedure/function must be defined before the main procedure/function begin statement

ie

Code: Pascal  [Select][+][-]
  1. procedure main;
  2. var x,y,z:integer;
  3.  
  4.   procedure sub1;
  5.   begin
  6.   end;
  7.  
  8.   procedure sub2;
  9.   begin
  10.   end;
  11.  
  12. begin  // start of code for procedure main
  13. end;
  14.  

Code: Pascal  [Select][+][-]
  1. procedure TMyMesh.LocalRender(const Params: TRenderParams);
  2.  
  3. begin   <* remove this
  4.  
  5.   procedure CreateMesh(AvatarTransform: TCastleTransform);
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Now that makes sense - it's illegal not because of the way I typed it, but because of the order I put it in, and Pascal order is very specific like anything else in coding. Thank you so much for the insightful help!

Unfortunately, I still get the same exact crash after fixing the order, even though I made extra sure to be specific about assigning a value to AvatarTransform first in the same way I would to any variable you use in a procedure.

Am I missing something else obvious?

dbannon

  • Hero Member
  • *****
  • Posts: 3212
    • tomboy-ng, a rewrite of the classic Tomboy
Unfortunately, I still get the same exact crash after fixing the order, ...

Seems unlikely its the exact same crash. Before you fixed the order, the code would not have compiled, you could not run it, so it could not crash ?

Anyway, if you are using Lazarus IDE, its way past time you learnt to use the debugger. Its built in and very effective.   As your code is very short, it is easy to step through that LocalRender procedure, line by line, and see where it goes bang. Once you know line, its usually pretty easy to guess what you have done wrong.

You will find that as you get a better feel for the syntax and comfortable with the debugger, you will be able to fix problems like these yourself, then you will be able to really start learning the system.

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
Unless I am missing something else obvious (which again I probably am), do you know where I can find the debugger?

I tried under "run", and there's debug mode, but not something like "launch debugger" or anything along those lines.

dbannon

  • Hero Member
  • *****
  • Posts: 3212
    • tomboy-ng, a rewrite of the classic Tomboy
No, the debugger is integrated in the IDE.

By default (I think) a new project has debugging turned on. (*)

Left click in the left gutter (that region to left of text content) and the line of text gets a red background. Then click Run.  The app will run to that line, the debugger waits there while you might examine variables etc.

Press F8 to step down (or 'over') to next line, F7 to dive down into the line instead. Keep stepping through until it all falls over.

There are buttons in top left block of button bar that do the same thing, look for the hint text.

(*) Worth understanding this, if the red background I mention becomes green, then the IDE is telling you it will not stop there, probably need to look at Project->ProjectOptions>Debugging.

And remember, this debugging code makes you app bigger and slower, when judging performance, create a new, debug free "release mode".

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

JPF12141999

  • Jr. Member
  • **
  • Posts: 88
I'm really sorry but I'm such a newbie when it comes to directions like "left gutter", even though I know how to code very well.

Can you show me using a screenshot or similar what the left gutter actually is?

 

TinyPortal © 2005-2018