Sevdat Posted June 24, 2023 Share Posted June 24, 2023 Good evening, I'm new so please have mercy)) Problem: I pointed out the place that results in the program to crash and named it RESULTS IN CRASH. When pressed run, starts running, then closes without opening, but the editor is still open. Refrence: Reverse engineered the 3rd person platformer demo camera code Task: I want to add a invisible ObjectStaticMesh box to PlayerDummy and when the box touches something it will change the distanceFromCenter variable so that it will move closer to the player position and won't phase through objects. I'm having problems figuring out how to detect collision. I also want to add movement without it affecting the overall physics on the player variable P.S I understand that there are other cameras, but I always create my own codes because then I know how they function...Refrence aside XD, first time quaternion. using System; using System.Collections; using System.Collections.Generic; using Unigine; [Component(PropertyGuid = "1de926e97387c334422e9503b576b68693459c2d")] public class MeshCameraControl : Component { private PlayerDummy camera; public ObjectMeshStatic player; public ObjectMeshStatic collisionBox; private void Init() { camera = node as PlayerDummy; // write here code to be called on component initialization Unigine.Console.Run("console_onscreen 1"); } float xDirection; float yDirection; float yLimit = 89.9f; float distanceFromCenter = 5.0f; float turnAngle = 180.0f; vec3 direction; vec3 rotateAroundX; vec3 rotateAroundY; private void Update() { xDirection -= Input.MouseDeltaRaw.x; yDirection = MathLib.Clamp(yDirection + Input.MouseDeltaRaw.y, -yLimit, yLimit); rotateAroundX = new quat(vec3.UP, xDirection) * vec3.FORWARD; rotateAroundY = new quat(MathLib.Cross(vec3.UP, rotateAroundX), -yDirection) * rotateAroundX; direction = rotateAroundY; collisionBox.WorldPosition = camera.WorldPosition; bool lol = collisionBox.GetCollision(1); (<----------------------------------------------------------RESULTS IN CRASH) camera.WorldPosition = player.WorldPosition + direction*distanceFromCenter; camera.ViewDirection = -direction; // write here code to be called before updating each render frame quat rotation = new quat(vec3.UP, xDirection + turnAngle); player.SetWorldRotation(rotation); Log.Message(lol + "\n"); } } Link to comment
Sevdat Posted June 24, 2023 Author Share Posted June 24, 2023 (edited) Noticed that pasting directly from vscode causes problems. I managed to make a collisionbox. It doesn't work perfectly and still phases throgh objects. It needs improvement. using System; using System.Collections; using System.Collections.Generic; using Unigine; [Component(PropertyGuid = "1de926e97387c334422e9503b576b68693459c2d")] public class MeshCameraControl : Component { private PlayerDummy camera; public ObjectMeshStatic player; private void Init() { camera = node as PlayerDummy; // write here code to be called on component initialization Unigine.Console.Run("console_onscreen 1"); } float xDirection; float yDirection; float yLimit = 89.9f; float distanceFromCenter = 5.0f; float turnAngle = 180.0f; float height = 1.0f; vec3 direction; vec3 rotateAroundX; vec3 rotateAroundY; private void Update() { vec3 boxMin = camera.WorldPosition - new vec3(0.0f, 0.0f, 1.0f); // Adjust the size of the bounding box as needed vec3 boxMax = camera.WorldPosition + new vec3(0.0f, 0.0f, 1.0f); BoundBox boundingBox = new BoundBox(boxMin, boxMax); List<Unigine.Object> colliders = new List<Unigine.Object>(); List<Unigine.Object> filteredColliders = new List<Unigine.Object>(); bool collisionDetected = Unigine.World.GetCollision(boundingBox, colliders); foreach (Unigine.Object item in colliders) { if (item.Name != "material_ball") {filteredColliders.Add(item);} } if (filteredColliders.Count != 0 && distanceFromCenter > 1.0f){distanceFromCenter -= 1;} if (filteredColliders.Count == 0 && distanceFromCenter < 6.0f){distanceFromCenter += 1;} xDirection -= Input.MouseDeltaRaw.x; yDirection = MathLib.Clamp(yDirection + Input.MouseDeltaRaw.y, -yLimit, yLimit); rotateAroundX = new quat(vec3.UP, xDirection) * vec3.FORWARD; rotateAroundY = new quat(MathLib.Cross(vec3.UP, rotateAroundX), -yDirection) * rotateAroundX; direction = rotateAroundY; camera.WorldPosition = player.WorldPosition + new vec3(0,0,height) + direction*distanceFromCenter; camera.ViewDirection = -direction; // write here code to be called before updating each render frame quat rotation = new quat(vec3.UP, xDirection + turnAngle); player.SetWorldRotation(rotation); } } Edited July 1, 2023 by Sevdat Link to comment
Sevdat Posted June 25, 2023 Author Share Posted June 25, 2023 (edited) Alright, long story short, I just created the Player Persecutor camera. For anyone who finds this instead of Player Dummy just use the Player Persecutor. Edited June 25, 2023 by Sevdat Link to comment
silent Posted June 26, 2023 Share Posted June 26, 2023 Sevdat Yes, it's better to use PlayerPersecutor for that task. Btw, to copy and paste code you can use special <code> tag: Thanks! How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN Link to comment
Sevdat Posted June 28, 2023 Author Share Posted June 28, 2023 Good day silent, I have a question. Why is the movement for rotation smooth when i use Input.MouseDeltaRaw.x but not when I use camera.PhiAngle? How can i make it smooth rotation? using System; using System.Collections; using System.Collections.Generic; using Unigine; [Component(PropertyGuid = "a95c371ff61b19f210c7b0a9e77741f4f29884c3")] public class cameraPersecutor : Component { private PlayerPersecutor camera; int x; int old = 0; // public ObjectMeshStatic player; private void Init() { camera = node as PlayerPersecutor; // write here code to be called on component initialization Unigine.Console.Run("console_onscreen 1"); x = 0; quat rotation = new quat(vec3.UP, 90.0f); camera.Target.SetWorldRotation(rotation); } private void Update() { // write here code to be called before updating each render frame camera.Distance = 5.0f; // if (x > 0) x -= 360; // if (x < 0) x += 360; if ((int)Math.Round(camera.PhiAngle) != old) x += Input.MouseDeltaRaw.x; old = (int)Math.Round(camera.PhiAngle); // x = (int)Math.Round(camera.PhiAngle); quat rotation = new quat(vec3.UP, (float)-x*0.4f); camera.Target.SetWorldRotation(rotation); Log.Message("phi:" + camera.PhiAngle + "\n"); Log.Message("x:" + x + "\n"); } } Link to comment
cash-metall Posted June 28, 2023 Share Posted June 28, 2023 Hello! what purpose are you using (int)Math.Round(camera.PhiAngle) if you want to control phi angle by youself - just set player.Fixed = true; this will turn off the internal logic for changing angles. if you want the target to follow the rotation of the camera, try doing there vec3 camera_rot = camera.GetWorldDirection(); camera.Target.SetWorldDirection(camera_rot, vec3.UP, MathLib.AXIS.Y) Link to comment
Sevdat Posted June 29, 2023 Author Share Posted June 29, 2023 (edited) Good day cash-metall, I want to keep the z axis stable and only rotate left and right. The problem with yours is that it will jitter and not have smooth turns just like getting values from: camera.PhiAngle ,however this for some reason does have smooth turns. Input.MouseDeltaRaw.x I noticed that the scaling is a bit different too. For example a distance of 5.0f will result in the circumference to be 900 MouseDeltaRaw. That's why I devided 360/900 to equalize the rotation of the material_ball. I'm also trying to make the camera move closer when it interacts with the ground or a wall. Also how can I get the MouseDeltaRaw as a circumference from the distance? That way the mesh will rotate with the camera at equal speeds. using System; using System.Collections; using System.Collections.Generic; using Unigine; [Component(PropertyGuid = "a95c371ff61b19f210c7b0a9e77741f4f29884c3")] public class cameraPersecutor : Component { private PlayerPersecutor camera; int x; int old = 0; // public ObjectMeshStatic player; private void Init() { camera = node as PlayerPersecutor; // write here code to be called on component initialization Unigine.Console.Run("console_onscreen 1"); x = 0; quat rotation = new quat(vec3.UP, 90.0f); camera.Target.SetWorldRotation(rotation); } float distance = 5.0f; private void Update() { // write here code to be called before updating each render frame camera.Distance = distance; x += Input.MouseDeltaRaw.x; quat rotation = new quat(vec3.UP, (float)-x*(360.0f/(900.0f))); camera.Target.SetWorldRotation(rotation); // x = (int)Math.Round(camera.PhiAngle); // camera.Target.SetWorldDirection(vec3.UP, camera_rot, MathLib.AXIS.Z); Log.Message("phi:" + old + "\n"); Log.Message("x:" + x + "\n"); } } With this I wanted to make it so that the MousleDeltaRaw doesn't change when the camera doesn't move because when escape is pressed and the mouse is free, movement makes the object rotate (int)Math.Round(camera.PhiAngle) Edited June 29, 2023 by Sevdat Link to comment
cash-metall Posted June 30, 2023 Share Posted June 30, 2023 "jitter" can be caused by the fact that the camera is updated after the nodes. you rotate the object to the camera position in the previous frame. to solve this problem, you can move the update to post-update: private void PostUpdate() // after camera update { if (!camera.Target) return; var dir = camera.GetWorldDirection(); // get current direction dir.z = 0; // ignore z if (dir.Length2 != 0) { dir.Normalize(); camera.Target.SetWorldDirection(dir, vec3.UP, MathLib.AXIS.Y); } return; } or force update camera before your logic private void Update() { if (!camera.Target) return; // force update camera camera.Controlled = true; camera.UpdateControls(Game.IFps); camera.FlushTransform(); camera.Controlled = false; var dir = camera.GetWorldDirection(); dir.z = 0; if (dir.Length2 != 0) { dir.Normalize(); camera.Target.SetWorldDirection(dir, vec3.UP, MathLib.AXIS.Y); } return; } Link to comment
Sevdat Posted July 1, 2023 Author Share Posted July 1, 2023 (edited) Good evening cash-metall, I'm using your code, using System; using System.Collections; using System.Collections.Generic; using Unigine; [Component(PropertyGuid = "a95c371ff61b19f210c7b0a9e77741f4f29884c3")] public class cameraPersecutor : Component { private PlayerPersecutor camera; int x; int old = 0; // public ObjectMeshStatic player; private void Init() { camera = node as PlayerPersecutor; // write here code to be called on component initialization Unigine.Console.Run("console_onscreen 1"); x = 0; quat rotation = new quat(vec3.UP, 90.0f); camera.Target.SetWorldRotation(rotation); } float distance = 5.0f; private void Update() { // write here code to be called before updating each render frame camera.Distance = 5.0f; vec3 camera_rot = camera.GetWorldDirection(); // camera.Target.SetWorldDirection(vec3.UP, camera_rot, MathLib.AXIS.Z); // force update camera camera.Controlled = true; camera.UpdateControls(Game.IFps); camera.FlushTransform(); camera.Controlled = false; var dir = camera.GetWorldDirection(); dir.z = 0; if (dir.Length2 != 0) { dir.Normalize(); camera.Target.SetWorldDirection(dir, vec3.UP, MathLib.AXIS.Y); } Log.Message("phi:" + old + "\n"); Log.Message("x:" + x + "\n"); } } it works well; however I have problems with detecting collision using the documentation. I made a collisionBox before for Player Dummy which I post again here. The camera moves backward when collision is detected and forward when not detected. vec3 boxMin = camera.WorldPosition - new vec3(0.0f, 0.0f, 1.0f); // Adjust the size of the bounding box as needed vec3 boxMax = camera.WorldPosition + new vec3(0.0f, 0.0f, 1.0f); BoundBox boundingBox = new BoundBox(boxMin, boxMax); List<Unigine.Object> colliders = new List<Unigine.Object>(); List<Unigine.Object> filteredColliders = new List<Unigine.Object>(); bool collisionDetected = Unigine.World.GetCollision(boundingBox, colliders); foreach (Unigine.Object item in colliders) { if (item.Name != "material_ball") {filteredColliders.Add(item);} } if (filteredColliders.Count != 0 && distanceFromCenter > 1.0f){distanceFromCenter -= 1;} if (filteredColliders.Count == 0 && distanceFromCenter < 6.0f){distanceFromCenter += 1;} I want to do something similar using Player Persecutor, but by getting the contact point of the camera's collision box. I've already read the documentation: https://developer.unigine.com/en/docs/latest/objects/players/persecutor/ https://developer.unigine.com/en/docs/2.17/api/library/players/class.playerpersecutor?rlang=cs&words=playerpersecutor#highlight but when I try to use GetContactPoint from Player Persecutor Class, the engine freezes and crashes. This is what I wrote: vec3 lol = camera.GetContactPoint(0); What am I doing wrong? How can I make it better? and how can I understand the documentation better? because although the class pages have the names of the methods, a basic example of how it can be used in programming isn't given under them which makes it hard to understand and use. Also In the console how can i see the collision boxes? To print messages it's "console_onscreen", but what is the command to show the invisible boxes? Edited July 1, 2023 by Sevdat Link to comment
moody_pooch Posted July 3, 2023 Share Posted July 3, 2023 Hi, Sevdat! Your program crashes at this line: vec3 lol = camera.GetContactPoint(0); because you are trying to get a point that doesn't exist. First of all check number of contacts and then use them: // check if the camera has contacts if (camera.NumContacts > 0) { Log.Message($"Num contacts: {camera.NumContacts}\n"); // apply some logic for each contact for (int i = 0; i < camera.NumContacts; i++) { vec3 point = camera.GetContactPoint(i); // visualizing camera contacts (for example) Visualizer.RenderPoint3D(point, 0.1f, vec4.MAGENTA, false, 10); Log.Message($"\tContact point: {point.x} {point.y} {point.z}\n"); } } If you want to use camera's boundBox, you can use already existing BoundBox of the camera: BoundBox bb = camera.BoundBox; // visualizer shows bb boundBox each frame Visualizer.RenderBoundBox(bb, camera.WorldTransform, vec4.BLUE); And if you create boundBox yourself min and max points should be the opposite points of the box diagonal (for example on this pic points B1 and D) More examples with creating BoundBox and finding intersections you can find here. And if you want to use Visualizer (like in examples for BoundBox and points earlier), you need to enable it first in Init(): Visualizer.Enabled = true; Best regards! 2 Link to comment
Recommended Posts