Hello,
I can move a squared 2D box and I have a rectangled 2D box in the center. I can collide the square with the rectangle, because I use the Rigidbody with an AddForce. The problem is that if I don’t press the arrow keys anymore, the square moves further.
How can I move the square only if I press an arrow key? I can move with the TranslationXY, but then the collision will not work.
I practiced further and found a solution. I don’t know if it’s a correct solution. Here I give a code example of what I did.
PlayerBody.LinearVelocity := TVector3.Zero;
if InputUp then
begin
direction := Vector3(0, 200, 0);
PlayerBody.LinearVelocity := direction * ThrustForce * SecondsPassed;
// PlayerBody.AddForce(direction * ThrustForce, True);
// PlayerBody.Parent.Translate(direction);
end;
if InputDown then
begin
direction := Vector3(0, -200, 0);
// PlayerBody.AddForce(direction * ThrustForce, True);
PlayerBody.LinearVelocity := direction * ThrustForce * SecondsPassed;
end;
if InputLeft then
begin
direction := Vector3(-200, 0, 0);
// PlayerBody.AddForce(direction * ThrustForce, True);
PlayerBody.LinearVelocity := direction * ThrustForce * SecondsPassed;
end;
if InputRight then
begin
direction := Vector3(200, 0, 0);
// PlayerBody.AddForce(direction * ThrustForce, True);
PlayerBody.LinearVelocity := direction * ThrustForce * SecondsPassed;
end;
I can’t press two arrow keys at the same time to move at an angle.
Greetings, Marco Kurvers from Holland.
Using physics to move the object will always result in it “going a bit further, on its own”. This includes moving
- by
TCastleRigidBody.AddForce
- by
TCastleRigidBody.ApplyImpulse
- by setting
TCastleRigidBody.LinearVelocity
to non-zero.
This is realistic, in reality the “teleportation” doesn’t exist
To do things in realistic way, use one of the above methods, and set LinearVelocityDamp, MaxLinearVelocity
to control it – to make the object not move too far.
If you definitely want unrealistic movement:
-
Moving the TCastleTransform by setting
Translation
(orTranslationXY
) should do the trick. And cause collisions (but be careful to not move the object too much into another, or the collision will explode in unpredictable direction).Note that you should at least set Animated to
true
when you do this, physics engine then knows you may reposition the object often yourself.You mentioned you tried it but the collision didn’t occur – this is strange. Can you submit a testcase to try out?
-
Note that if you don’t want the object to be ever affected by physics (only act as collider) then just set Dynamic to
false
. -
A useful hack is also to set
LinearVelocity
to zero in next frame, to stop the movement. I think this is effectively what your code is doing This is OK too, and may be simpler than AD 1.
All in all, your solution, from a quick glance, is like AD 3, and yes, that’s OK and officially supported way of doing this. I hope rest of this information is helpful
I have tested with Animated to True and used with TranslationXY. But the collision didn’t occur.
This is the test design.
This is the code that I have changed.
procedure TViewMain.Start;
begin
inherited;
Player.TranslationXY := Vector2(0, -457);
end;
procedure TViewMain.Update(const SecondsPassed: Single; var HandleInput: Boolean);
var
direction: TVector3;
begin
inherited;
{ This virtual method is executed every frame (many times per second). }
Assert(LabelFps <> nil, ‘If you remove LabelFps from the design, remember to remove also the assignment “LabelFps.Caption := …” from code’);
LabelFps.Caption := 'FPS: ’ + Container.Fps.ToString;
// PlayerBody.LinearVelocity := TVector3.Zero;
if InputUp then
begin
// direction := Vector3(0, 200, 0);
// PlayerBody.LinearVelocity := direction * ThrustForce * SecondsPassed;
// PlayerBody.AddForce(direction * ThrustForce, True);
Player.TranslationXY := Player.TranslationXY + Vector2(0, 5);
end;
if InputDown then
begin
// direction := Vector3(0, -200, 0);
// PlayerBody.AddForce(direction * ThrustForce, True);
// PlayerBody.LinearVelocity := direction * ThrustForce * SecondsPassed;
Player.TranslationXY := Player.TranslationXY + Vector2(0, -5);
end;
if InputLeft then
begin
// direction := Vector3(-200, 0, 0);
// PlayerBody.AddForce(direction * ThrustForce, True);
// PlayerBody.LinearVelocity := direction * ThrustForce * SecondsPassed;
Player.TranslationXY := Player.TranslationXY + Vector2(-5, 0);
end;
if InputRight then
begin
// direction := Vector3(200, 0, 0);
// PlayerBody.AddForce(direction * ThrustForce, True);
// PlayerBody.LinearVelocity := direction * ThrustForce * SecondsPassed;
Player.TranslationXY := Player.TranslationXY + Vector2(5, 0);
end;
end;
I know it only works through the rigidbody. In Unity, I have the same problem. It is recommended to use the velocity, to leave the calculation and collision checking to the rigidbody. That’s why I’ve been thinking about whether Castle Game Engine also has a velocity. Not the velocity like in Unity, but the LinearVelocity that does the same.
I just need to find something like a Physics Material. In Unity, I can add it to the rigidbody, so that a ball can keep bouncing off the walls.
Let’s continue with this test first. I want to make the beam move and place more transforms of the beam.
I cannot place a testcase here. I tried that. But I will say thank you for the help. If I find more problems or solutions, I’ll let you know. Thanks for the help.
I’m doing a bit better, but I still have problems. If I give the SecondsPassed in the Vector3 direction, the collisions only work for a short time. If I don’t give the SecondsPassed, it will work. Also, it doesn’t work if the box or beam go too fast. It seems as if the collision is being ignored.
Maybe I can show you on the discord. But I don’t know how the Discord works and is it public?
OK, I’m happy it helped!
As for the testcase – if you’ll have time, I’m still interested in a testcase (code + data) showing the situation when moving something by Translation
/TranslationXY
makes the collision not occur. We’d like to fix it, or at least investigate, because the collision (albeit unnatural in this case, because the object was teleported) should be detected and the objects should “bounce off” each other. The code and design you show so far look OK You can attach a tescase here e.g. as a zip file.
Our TCastleRigidBody and TCastleCollider expose properties that have similar role as Unity’s PhysicsMaterial. In particular see TCastleCollider.Friction
, TCastleCollider.Restitution
.
Note: The term “material” in our Castle Game Engine is reserved for stuff that determines “how does object look like”, never “how it behaves”. So we have nodes like TMaterialNode
, TUnlitMaterialNode
, TPhysicalMaterialNode
– but the latter is not related to Unity “Physical Material”, instead TPhysicalMaterialNode
says to use modern physically-correct rendering equations.
Hm, I would need to see a testcase to understand the issue and fix.
You’re welcome to send it here or on Discord, it’s all public, others can see the question (and help too, or learn from the answers). Note that I’m not available on Discord right now, though I’m also not available on the forum all the time I am packing for a short vacation until Wednesday now. But wherever you will post it, I will get to it!
I would suggest to post it here on the forum, to keep the conversation connected, unless it’s an unrelated issue.
Here I have the zip file with the name Overkant. I will try to make a testgame to move with the box and go up. With the WallTop I will make a trigger so that the game can say: Congratulations
Overkant.zip (52.5 MB)
I hope that you can open the project to see what I did.
Thank you for the testcase!
Things I noticed:
-
Since this is 2D game, you should select
Mode2D
for all your colliders. Otherwise, they are actually very very thin rectangles in the 3D world (even though they seem to be 2D) and collisions between them may be missed.To solve it, just select in the editor (holding Ctrl) all
TCastleRigidBody
instances and then click onMode2D
.For future physics colliders/rigid bodies, add them using “Add Behavior → Physics → Collider (2D) → …” menu items.
-
Note that when you do AD 1, the auto-calculated mass of the
Beam
will change (as it is no longer thin, underneath we make it large in Z), and you will need to apply more force to actually move it.One solution is just to multiply
ThrustForce
by 100 and it will do the trick.Another solution would be to set explicit (non-zero)
Mass
forBeamCollider
. Then it will require the same force, regardless ofMode2D
.
See screenshots. After doing these 2 things, everything seems to nicely collide with each other
Now I understand this statement. The correct thing to do is not multiply the parameter to AddForce
by SecondsPassed
. So the uncommented code that you send is already good,
BeamBody.AddForce(Vector3(beamSpeed * ThrustForce, 0, 0), True);
The reason is that AddForce
internally already effectively multiplies the given parameter by SecondsPassed
. See docs of AddForce :
If you want to keep applying this force (e.g. it is a wind that continues pushing in given direction) you should call this method every frame. It automatically accounts for the delta time (because the force will actually be applied later, with delta time, to velocity) so no need to multiply the arguments with SecondsPassed.
It works well. Beautiful. Another question is: how can I bounce like a ball, without the beam having to pull up again? In breakout games, you don’t see that the ball has to keep pulling up to get back up to speed. In Unity, the physics material gives a collision effect without the use of the addforce. The addforce is then only needed to shoot the ball away with a mouse click. Maybe you also have such an effect in CGE, but I don’t know how yet.
I’ve tried a BeamBody.LinearVelocity, the line in comments, but when I start I don’t see the beam anymore.
Sorry to talk about Unity a lot, but I’m trying to find something similar. And for me, it’s about the Pascal language. That suits me better than C#. Despite the fact that I made a beautiful breakout game and took 4 years to complete. Now I have to try it in CGE. But I still have a lot to learn and test.
I hope you’ll be there again next year when there’s another Pascal café in IJsselstein. I don’t think I’ll be able to come to Cologne in October.
Thanks for the good words! And yes, I will likely be at Pascal Cafe in IJsselstein, if it will be organized again in 2025.
Comparisons with Unity are welcome, no worries. I mean: we do “compete” when it comes to a general-purpose game engine. If we miss something compared to Unity, surely I want to know about it, don’t hesitate to say things like “Unity allows to do X, how can I do it in CGE”. I’m not sure if the word “compete” is deserved now (we’re a tiny tiny game engine, looking at our resources, compared to Unity ) but we have big ambitions.
BTW (sorry if I pointed you do this already, I have weak memory) : If you come from Unity, this document may be helpful: Castle Game Engine Overview For Unity Developers | Castle Game Engine .
The physics things “bounce off” each other automatically. I mean, there’s nothing you should do to make it happen, if the ball is a regular physics object (with TCastleRigidBody
and Dynamic
= true
) then it will bounce off other objects. Be sure to not set the ball’s LinearVelocity
, because if you set it, you effectively override physics engine calculations (at least from the last frame).
Configure the Restitution
I mentioned above to configure “how much” it bounces.
And using AddForce
or ApplyImpulse
(e.g. in response to collision, e.g. from OnCollisionEnter
event) is only necessary if you want to really apply additional force at given moment.
Hopefully this helps, if I misunderstand what you mean – I will need a video recording of what you want and/or another testcase to see how it fails
The beam object now collides with the sides without using the OnCollisionEnter, but it still works very strangely. I now have two beam objects. One that works with a continuous AddForce and one that has an AddForce that only runs once.
I’ll try to make a video so you can see what happened and how I did it in Unity. With a physics material it works fine and everything continues at its own speed. I would like to show it on the Discord when you are ready. We can then immediately find something with questions and answers to get the same thing in CGE.
Here I have the project with changes again.
Overkant.zip (52.5 MB)
Here I provide screenshots so you can see what I do with the Beam in Unity.
And the Beam Class with a dutch name Barriere.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Barriere : MonoBehaviour
{
public int direction;
public float speed;
public int damage = 5;
public float force = 200;
private bool isStarted = false;
private GameObject player;
private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
rb = GetComponent();
player = FindObjectOfType().gameObject;
}
// Update is called once per frame
void Update()
{
if (player.GetComponent<Player>().isBoven)
{
rb.velocity = Vector2.zero;
}
else
{
if (!isStarted)
{
isStarted = true;
rb.AddForce(new Vector2(direction * force * speed * Time.deltaTime, 0), ForceMode2D.Force);
}
}
}
}
Beautiful, I have a video for you how I do this in Unity. Many property’s are the same, but it’s the physics material that make the bouncing.
2024-08-16 13-24-52.zip (20.0 MB)
I hope that the file in the zip will work. If I will place the video without the zip in here, I get an error.
Sorry for getting quiet in this thread, I have in TODO to read and investigate new things you report from post How to move a scene TCastleScene with the ridigbody without AddForce - #11 by M.A.Kurvers . I’ll get to it ~next week, sorry for delay → lots of urgent things happened lately
Hi Michalis. We just have to be able to make time ourselves. It doesn’t run away. In between, I’m experimenting a lot with the physics to make sprites move without friction, so no friction. There should be a way to keep a ball moving continuously without it slowing down (such as in multiple pong and breakout games). In any case, it doesn’t work by invoking the AddForce after every frame. As soon as the AddForce takes a shot from the ball, the movement must be registered by the rigid body without slowing down and the collisions. Because there is no physics material in CGE, it must be able to operate automatically with a friction at 0. So that doesn’t work yet.
I’m going to try to find a solution. Maybe I’ll make a video of it when I find something.
Hello, this days I was making some some test about 2D collision, and I started a “small” arconoid game.
In my test game works nice.
See my code, may be can help: GitHub - Blueicaro/Arcanoid_CEG: Testing to make a Arcanoid game in Castle Game Engine
/BlueIcaro
Hello. I opened it in CGE, but I see everything black. Also, there is no control to be found in the code. Just a bare-bones GameViewMain.
Hello, I’m sorry I forget push the changes to the git repository.
By the moment it only a “demo” to learn, If you push space bar the ball starts to bounce again the black border. Also you can user arrow keys to move the small bar.
/BlueIcaro
P.D. See main branch: GitHub - Blueicaro/Arcanoid_CEG: Testing to make a Arcanoid game in Castle Game Engine
Hello, I compiled this demo, on linux with lasted version of CGE downloaded from github.
Also I tried in W11, also with lasted verssion of CGE and It’s works nice.
Which version of CGW do use?. May this is the problem.
In both test I use lasted estable lazarus version (3.4)
The CGE developers may be have more info
/BlueIcaro