This (implement ray collision example that avoids transparent objects) is still a TODO.
Other than that, I think I managed to catch up with all pending questions / tasks on forum today
This (implement ray collision example that avoids transparent objects) is still a TODO.
Other than that, I think I managed to catch up with all pending questions / tasks on forum today
Many thanks, I now got it working when using the CGE editor.
Now I want to add the effect on every scene created in code but it does not work.
I have (heavily stripped down type of TAvatar):
`
type
TAvatar = class
private
type TPersonalia = class
FirstName: string;
end;
var Personalia: TPersonalia;
Transform: TCastleTransform;
face_west, face_east, face_north, face_south: TCastleScene: TCastleScene;
LightUp: TCastleDirectionalLight;
constructor TAvatar.Create(firstname: string);
begin
Personalia := TPersonalia.Create;
Personalia.FirstName := firstname;
Transform := TCastleTransform.Create(Transform);
face_west := TCastleScene.Create(face_west);
Transform.Add(face_west);
face_east := TCastleScene.Create(face_east);
Transform.Add(face_east);
face_north := TCastleScene.Create(face_north);
Transform.Add(face_north);
face_south := TCastleScene.Create(face_south);
Transform.Add(face_south);
LightUp := TCastleDirectionalLight.Create(LightUp);
LightUp.Exists:= true;
LightUp.Intensity:= 3;
LightUp.RenderLayer:= rlParent;
face_west.Add(LightUp);
face_east.Add(LightUp);
face_north.Add(LightUp);
face_southt.Add(LightUp);
ViewMain.Viewport.Items.Add(Transform);
(in Start section:)
Player := TAvatar.Create('jack');
CreateColorEffect(player.face_west);
When I add other scenes
CreateColorEffect(player.face_east);
CreateColorEffect(player.face_north);
only the last one gives the effect.
only the last one gives the effect.
Iâd have to see the code where you update the effect to tell whatâs wrong.
If you have something similar to the previous code you posted, note:
You need to store different âEffectColorFieldâ for each scene you may want to highlight.
In âTViewMain.Updateâ you need to turn off the old highlight, turn on the new highlight.
You could e.g. use behaviors Behaviors | Manual | Castle Game Engine to manage this information, e.g. declare
type
THighlightBehavior = class(TCastleBehavior)
EffectColorField: ..;
end;
Then when adding the effect to SomeScene
, add also the behavior:
EffectColorField := ...; // create it as before
HighlightBehavior := THighlightBehavior.Create(...);
HighlightBehavior.EffectColorField := EffectColorField;
SomeScene.AddBehavior(HighlightBehavior);
In Update
, track the old and new highlighted objects:
type
TViewXxx = class
private
CurrentHighlight: THighlightBehavior;
end;
...Update(...);
var
NewHighlight: THighlightBehavior;
begin
... // whatever you had previously
if Viewport.TransformUnderMouse <> nil then
begin
NewHighlight := Viewport.TransformUnderMouse.FindBehavior(THighlightBehavior) as THighlightBehavior;
if NewHighlight <> CurrentHighlight then
begin
if CurrentHighlight <> nil then
CurrentHighlight.Send(Vector3(1, 1, 1));
if NewHighlight <> nil then
NewHighlight.Send(Vector3(1.3, 1.3, 1.3));
CurrentHighlight := NewHighlight;
end;
end;
end;
Thanks.
I get a few errors:
If you can see what is wrong here, otherwise I think I have to upload another testcase.
And I donât know if it is possible but instead of changing colors for all 8 different scenes that are part of one Transform I would like to change the parent color (of the upperTransform).
If you can see what is wrong here, otherwise I think I have to upload another testcase.
HighLight.EffectColorField
â I meant HighLightBehavior.EffectColorField
CurrentHighlight.Send
â I meant CurrentHighlight.EffectColorField.Send
, NewHighlight.Send
â I meant NewHighlight.EffectColorField.Send
.
It seems you missed the logic behind my changes (otherwise youâd be able to fix these yourself ). If anything is unclear in how this works, please ask. The idea of behaviors is explained, with examples, on Behaviors | Manual | Castle Game Engine .
And I donât know if it is possible but instead of changing colors for all 8 different scenes that are part of one Transform I would like to change the parent color (of the upperTransform).
For now, you cannot apply effects on parent TCastleTransform
to affect all children of TCastleScene
. You have to apply the effect on each TCastleScene
.
It seems you missed the logic behind my changes (otherwise youâd be able to fix these yourself ). If anything is unclear in how this works, please ask. The idea of behaviors is explained, with examples, on Behaviors
Yes, I admit that this is confusing. I have tried it again but cannot get it to work.
Would you please take a look at the attachment? Thanks.
light-test.zip (34.4 MB)
Yes, I admit that this is confusing. I have tried it again but cannot get it to work.
Would you please take a look at the attachment? Thanks.light-test.zip (34.4 MB)
The declaration
HighLightBehavior: TCastleBehavior;
should be changed to
HighLightBehavior: THighLightBehavior;
(otherwise you get compilation error at âHighlightBehavior.EffectColorField := ...
â because the class TCastleBehavior doesnât contain the EffectColorField field).
Actually HighLightBehavior: THighLightBehavior;
should not be declared in TViewMain
, it should be local, only declared and used when we create it.
Then the code compiles but crashes â because you try to use the EffectColorField: TSFVec3f;
declared in class TViewMain
. This has to be removed, EffectColorField
should only be inside THighLightBehavior
.
This required a bit of rework â you need to have 1 THighLightBehavior instance for each of your scenes.
So you cannot have
HighlightBehavior := THighlightBehavior.Create(HighlightBehavior);
HighlightBehavior.EffectColorField := EffectColorField;
Scene1.AddBehavior(HighlightBehavior);
Scene2.AddBehavior(HighlightBehavior);
See how I remade the logic to create the effect, and THighlightBehavior instance, and attach it to scene in procedure AddColorEffect(const Scene: TCastleScene)
.
Then we can remove pieces of old code.
TViewMain.LightupColor is no longer necessary.
These lines are no longer necessary, we handle highlight in more generic way using behaviors:
if Viewport.TransformUnderMouse = Scene1 then
EffectColorField.Send(Vector3(1.3, 1.3, 1.3))
else
EffectColorField.Send(Vector3(1, 1, 1));
if Viewport.TransformUnderMouse = Scene2 then
EffectColorField.Send(Vector3(1.3, 1.3, 1.3))
else
EffectColorField.Send(Vector3(1, 1, 1));
Please see
unit GameViewMain;
interface
uses Classes,
CastleVectors, CastleComponentSerialize,
CastleUIControls, CastleControls, CastleKeysMouse, CastleScene, CastleTransform, CastleViewport, X3DNodes, X3DFields;
type
This file has been truncated. show original
â this is my minimal modification to your example, and it compiles and works nicely â any of 2 characters get highlighted when mouse is over them
Do compare my version with your version to see all changes I did If you donât have your file in a version control, you can compare files e.g. using http://meldmerge.org/ .
This was a tough one for me so many thanks for sorting this out!
Then I tried to put procedure AddColorEffect in a separate one, out of the Start procedure because my character scenes are created in code procedures during game play and not at start. (it was just in the testcase).
I got an error on âSelfâ with HighLightBehavior := THighlightBehavior.Create(Self); (Self not found).
When I changed it to HighLightBehavior := THighlightBehavior.Create(HighLightBehavior ); I got a note but the code compiled then crashed. (obviously because HighlightBehavior was not created).
Then I changed it in procedure TViewMain.AddColorEffect and then it worked.
So as procedure AddColorEffect without putting it in TViewMain did not work, I donât know why, it probably could not find the other references to HighlightBehavior because they were part of TViewMain?
I am happy this works now, thanks again!
I got an error on âSelfâ with HighLightBehavior := THighlightBehavior.Create(Self); (Self not found).
When I changed it to HighLightBehavior := THighlightBehavior.Create(HighLightBehavior ); I got a note but the code compiled then crashed. (obviously because HighlightBehavior was not created).
Then I changed it in procedure TViewMain.AddColorEffect and then it worked.
So as procedure AddColorEffect without putting it in TViewMain did not work, I donât know why, it probably could not find the other references to HighlightBehavior because they were part of TViewMain?
When you create a component (any class descending from Pascal TComponent
, this includes a lot of CGE classes or classes derived from them, like TCastleBehavior
and THighlightBehavior
) then you need to provide âownerâ instance as the first parameter.
SomeInstance := TSomeClass.Create(SomeOwner);
The SomeOwner
will be responsible for freeing the SomeInstance
automatically, so that freeing SomeOwner
will also free SomeInstance
.
The article Modern Object Pascal Introduction for Programmers | Castle Game Engine may be helpful, from the paragraph
To avoid the need to explicitly free the instance, one can also use the
TComponent
feature of âownershipâ
What should be the owner? There are really many possible options.
You can pass Self
, if you are within the method of another component. If you are within a method of some view (like TViewMain) then Self
means the current view instance and is equivalent to the global variable ViewMain
.
If you are not implementing a view method (but e.g. a simple procedure), you could use global variable ViewMain
. Or pass the owner as a special parameter of the procedure, e.g.
procedure MyProcedureToCreateSomething(const SomeOwner: TComponent);
begin
SomeInstance := TSomeClass.Create(SomeOwner);
end;
and use it like MyProcedureToCreateSomething(Self)
from another method. See Modern Object Pascal Introduction for Programmers | Castle Game Engine for a (very terse, I admit) description of Self
.
In a view, you can also use FreeAtStop
as the owner, to make something freed when the view stops.
Note that youâre not forced to provide an owner. You can always use just nil
. But be sure to free the SomeInstance
yourself then (by e.g. FreeAndNil(SomeInstance)
at some point) otherwise you will have a memory leak.
SomeInstance := TSomeClass.Create(nil); // Owner is nil, we will free it manually
try
SomeInstance.DoSomething;
finally
FreeAndNil(SomeInstance);
end;