ROBLOX Camera Lock-on causes spinning - lua

I made a Lock-On Script for ROBLOX that locks onto a specific enemy, but follows the player from a shoulder-surfing view point.
The problem is, when approaching the said enemy or entity that is locked on, and jumping on their head or above them; causes the player to spin when move only forward.
I'm aware that the problem comes from the movement system going towards where the Camera is looking, which is what I want; however, preferably with a seamless transition when moving above the enemy.
-- Declare variables
local player = game.Players.LocalPlayer
local camera = game.Workspace.CurrentCamera
local runService = game:GetService("RunService")
local dummy = workspace.Dummy
local target = workspace.Lock
camera.CameraType = Enum.CameraType.Scriptable
camera.CameraSubject = target
local angle = 0
-- Wait a frame for camera to load
wait()
-- Update camera on RenderStepped to get smooth motion
runService.RenderStepped:connect(function()
local character = player.Character
-- Check if character and torso exist (in case character is dead)
if character and character.Torso and character.Head then
local torso = character.Torso
local head = character.Head
local ZPosition = Vector3.new(head.CFrame.X, head.CFrame.Y + 2, head.CFrame.Z)
local ZCFrame = CFrame.new(head.CFrame.X, 1, head.CFrame.Z)
local XPosition = Vector3.new(head.CFrame.X + 5, head.CFrame.Y + 2, head.CFrame.Z)
camera.CFrame = CFrame.new(ZPosition, target.Position) * CFrame.new(2, 0, 7)
camera.Focus = CFrame.new(target.Position)
end
end)
MP4/GIF

The camera spinning when on top of the entity's head could be because you're trying to reach a point that you're vertically on top of.
To help you imagine this, visualize if you were trying to use a compass that points towards the north pole to reach the north pole, and you can only walk in the direction the compass is pointing. Once you got near the north pole, the compass would point towards it. But, if you kept walking forwards, eventually you'd walk OVER the north pole and pass over it. Then the compass would spin around and point backwards, so you'd walk backwards. Eventually you'd walk over top of it again and the compass would flip around again.
Eventually you'd get to a point where you're going back and forth over top of it very fast but you never get QUITE directly over top of it. Because the compass always points towards the north pole, you would see the compass spinning around very quickly because you're moving around it very quickly very close to it, but never exactly over top. The closer you get, the smaller movements make a bigger impact on the direction of the compass.
I think this is what's happening, where the camera is locked onto the target and the player is walking forwards. Once you get ON TOP of the target, the camera tries to keep pointing towards the target, but since you're so close, you pass back and forth over the point on the target the camera is pointing to and it whips around trying to point to it.
Maybe you could insert a check like this:
if (distanceToTarget.X >= 1 meter) then
camera.pointAtTarget(); --Point at the locked on target as your script would
else
camera.pointNormally(); --Point straight ahead as it normally would if there was no locked target
end
The distance is up to you to determine but the general idea is that if you get close enough to the target that the camera starts whipping all around, it will stop tracking and function normally. Alternatively, if the issue only occurs when ABOVE the target, then try including another condition to check if the player is directly above the target and to stop tracking then.

Related

Roblox: Touched event returns incorrect position of projectile

I've made a cannon in Roblox, it uses part velocity to launch cannon ball projectiles out the cannon. It attaches a function to the touched event for the cannon ball that's taken from server storage and moved to workspace. The cannon ball when touched and the part touched is not part of the cannon itself generates an explosion.
The problem is that it works for roughly 20 shots, its a different amount of successful cannon shots each time however after a few the cannon ball's position starts return incorrectly and as a result the explosions explode in mid air.
To figure out the root cause of this I've tried removing the explosion and making it spawn a part there instead and after roughly 20 shots it will start to make the parts appear in mid air instead of where the cannon ball actually collided. I've tried both making the cannon ball collide and non collide which made no difference. It appears that the position within the touched event function is not returning the true position of where the part was touched in 3D space.
local function cannonMC1CTSEvent(player, mousePos)
local cannonBall = game.ServerStorage.cannonball:Clone()
cannonBall.Position = script.Parent.barrel.CFrame.Position
cannonBall.Parent = workspace
physicsService:SetPartCollisionGroup(cannonBall, "cannonBall")
script.Parent.barrel.CFrame = CFrame.new(script.Parent.barrel.CFrame.Position, mousePos)
cannonBall.CFrame = CFrame.new(script.Parent.barrel.CFrame.Position, mousePos)
cannonBall.Velocity = cannonBall.CFrame.LookVector * 256
local function generateExplosion()
explosion = Instance.new("Explosion")
explosion.BlastRadius = 2
explosion.BlastPressure = 100
end
generateExplosion()
cannonBall.Touched:Connect(function(touched)
if touched.Parent.Name ~= "cannon" then
explosion.Position = cannonBall.Position
cannonBall:Destroy()
explosion.Parent = workspace
generateExplosion()
end
end)
Here is the code for the cannon ball, the code fires a cannon ball every time the user clicks which is done locally using a remote event to tell server to fire the cannon. I've been baffled with this issue and my first guess would be that it's just Roblox Part.Velocity being buggy. Thankyou in advance!
I've spent about 5 hours today trying to find the root of the issue. It's the Roblox touched event. It is inaccurate at detecting collision of moving parts. I figured out this was the issue by checking whether ArePartsTouchingOthers was true or false, the times the explosion was in mid air and inaccurate to the visual position of the cannonball when it collides was false whereas when it was correctly positioned it was true. Therefore I am going to remake my code around using ArePartsTouchingOthers instead of using the touched event.
making an explosion before it touches something is a bad idea so try running the function when it collides. EDIT: you never gave the explosion a parent (but also don't pre-create the explosion) so try:
local function generateExplosion()
explosion = Instance.new("Explosion",game.Workspace)
explosion.BlastRadius = 2
explosion.BlastPressure = 100
end

Why is the angle of the mouse and the player changing when the player is outside of the camera deadzone?

This a camera module designed in Lua for use in the Love2D framework. When you set up the camera, it takes a 'deadzone' where, when the followed object is within this 'deadzone', the camera doesn't move. The 'deadzone' is shown by the green corners around the centre of the screen.
Here is what it looks like in my game when I'm just moving around.
When the player character is within the deadzone, shooting works as expected. I am relatively novice at the Lua programming language, but in previous projects I've found that this code works and makes sense for finding the direction for a bullet, where mx and my are the mouse coordinates, and px and py are the player coordinates.
direction = math.atan((my-py)/(mx-px))
if px > x then direction = direction + math.pi end
When I'm within the deadzone and shooting
But as the player moves outside of the deadzone and shoots at the same time, it adds a seemingly random angle to the direction.
Moving and shooting
I have no idea what is going on. I've been using this code for finding mx and my:
mx, my = love.mouse.getPosition()
mx = (x-love.graphics.getWidth()/2)/window.scale+camera.x
my = (y-love.graphics.getHeight()/2)/window.scale+camera.y
Which follows the mouse perfectly.
Showing that it is finding the correct mouse position
So I have no idea what is going on, because I presume px and py are correct because if they weren't, it would be drawing them to the wrong location.
Hopefully this all makes sense and I'm happy to clarify anything that isn't clear or exhibit any more code.

My object is glitching out because of the way I make it move

I'm working on a game with my friend, and we are making an object move around a house and go to random points. The thing is, if it moves higher up on the X axis then goes down then it starts shaking and acting weird.
path:ComputeAsync(character.Position, workspace:WaitForChild("ModelsMain").SleepBag.SLEEP.Position)
waypoints = path:GetWaypoints()
for _, wp in pairs(waypoints) do
local tweenInfo = TweenInfo.new(.6, Enum.EasingStyle.Linear)
local tween = TweenService:Create(character, tweenInfo, {CFrame = CFrame.new(wp.Position.X, character.CFrame.Y, wp.Position.Z)})
tween:Play()
tween.Completed:Wait(2)
--character.CFrame = CFrame.new(wp.Position.X, wp.Position.Y, wp.Position.Z)
end
wait(5)
local baggy = game:GetService("ServerScriptService").moneybag:Clone()
baggy.Parent = workspace:WaitForChild("Moneys")
baggy.Position = character.Position
I am aware that character.CFrame.Y isn't the best but I can't really figure out how to keep it on the ground. (RayCasting?)
I have to use Tween because it's an object and it can't have a humanoid.
Here is a video. In this video, you can see the object shake and then when it reaches it's point then it'll drop "dead", as I call it.
One of the problems with this script is that the time for the tween to complete is inconsistent. Currently, it is setup to take 0.6 seconds to move to each waypoint. The issue is that the distance between the waypoints are not taken into account. If it is far away, the character will move very fast. If it is close, the character will move slower.
To fix this, either the speed of the tween should be based off of the distance from the character to the waypoint, or another method should be used to move the character such as humanoids (see other solutions below).
Another issue causing the bug could actually be the usage of character.CFrame.Y. This may interfere with the physics system which would cause very odd bugs related to movement. There are many different methods of fixing this.
One solution is to disable the physics while tweening, though that is hacky and would cause other issues later on. Another is to use a different method that avoids modifying the Y axis. Once again, it would probably be best to use a humanoid however if that is not an option see tweening an object along one axis.

How to temporarily freeze a node in front of the camera using ARKit, SceneKit in Swift

I built a complete structure as a node (with its child nodes) and the user will walk through it using ARKit.
At some point, if the user cannot continue because of some real obstacle in the real world, I added a "pause" button which should freeze whatever the user currently sees in front of the camera, the user could then move freely to some other open space and when the user will release the pause button he/she will be able to resume where they left off (only someplace else in the real world).
A while ago I asked about it in the Apple Developer forum and an Apple Frameworks Engineer gave the following reply:
For "freezing" the scene, you could transform the anchor's position (in world coordinates) to camera coordinates, and then anchor your content to the camera. This will give you the effect that the scene is "frozen", i.e., does not move relative to the camera.
I'm currently not using an anchor because I don't necessarily need to find a flat surface. Rather, my node is placed at a certain position relative to where we start at (0,0,0).
My question is how do I exactly do what the Apple engineer told me to do?
I have the following code which I'm still stuck with. When I add the node to the camera (pointOfView, last line of the code below), it does freeze in place, but I can't get it to freeze in the same position and orientation as it was before it was frozen.
#IBAction func pauseButtonClicked(_ sender: UIButton) {
let currentPosition = sceneView.pointOfView?.position
let currentEulerAngles = sceneView.pointOfView?.eulerAngles
var internalNodeTraversal = lastNodeRootPosition - currentPosition! // for now, lastNodeRootPosition is (0,0,0)
internalNodeTraversal.y = lastNodeRootPosition.y + 20 // just so it’s positioned a little higher in front of the camera
myNode?.removeFromParentNode() // remove the node from the Real World view. Looks like this line has no effect and just adding the node as a child to the camera (pointOfView) is enough, but it feels more right to do this anyway.
myNode?.position = internalNodeTraversal // the whole node is moved respectively in the opposite direction from the root to where I’m standing to reposition the camera in my current position inside the node
// myNode?.eulerAngles = (currentEulerAngles! * -1) — this code put the whole node in weird positions so I removed it
myNode?.eulerAngles.y = currentEulerAngles!.y * -1 // opposite orientation of the node so the camera will be oriented in the same direction
myNode?.eulerAngles.x = 0.3 // just tilting it up a little bit to have a better view, more similar to the view as before it was locked to the camera
// I don’t think I need to change the eulerAngles.z
myNode!.convertPosition(internalNodeTraversal, to: sceneView.pointOfView) // I’m not sure I wrote this correctly. Also, this line doesn’t seem tp change anything
sceneView.pointOfView?.addChildNode(myNode!) // attaching the node to the camera so it will remain stuck while the user moves around until the button is released
}
So I first calculate where in the node I'm currently standing and then I change the position of the node in the opposite direction so that the camera will now be in that position. That seems to be correct.
Now I need to change the orientation of the node so that it will point in the right direction and here things get funky. I've been trying so many things for days now.
I use the eulerAngles for the orientation. If I set the whole vector multiplied by -1, it would show weird orientations. I ended up only using the eulerAngles.y which is the left/right orientation and I hardcoded the x orientation (up/down).
Ultimately what I have in the code above is the closest that I was able to get. If I'm pointing straight, the freeze will be correct. If I turn just a little bit, the freeze will be pretty close as well. Almost the same as what the user saw before the freeze. But the more I turn, the more the frozen image is off and more slanted. At some point (say I turn 50 or 60 degrees to the side) the whole node is off the camera and cannot be seen.
Somehow I have a feeling that there must be an easier and more correct way to achieve the above.
The Apple engineer wrote to "transform the anchor's position (in world coordinates) to camera coordinates". For that reason I added the "convertPosition" function in my code, but a) I'm not sure I used it correctly and b) it doesn't seem to change anything in my code if I have that line or not.
What am I doing wrong?
Any help would be very much appreciated.
Thanks!
I found the solution!
Actually, the problem I had was not even described as I didn't think it was relevant. I built the AR nodes 2 meters in front of the origin (-2 for the z-coordinate) while the center of my node was still at the origin. So when I changed the rotation or eulerAngles, it rotated around the origin so my nodes moved in a large curve and in fact also changed their position as a result.
The solution was to use a simdPivot. Instead of changing the position and rotation of the node itself, I created a translation matrix and a rotation matrix which was at the point of the camera (where the user is standing) and I then multiplied both matrices. Now when I added the node as a child of the camera (pointOfView) this would freeze the image and in effect show exactly what the user was seeing before it was frozen as the position is the same and the rotation is exactly around the user's standing position.

Simulating the "Change Directions on Ice" Effect

I really hope someone understands what the effect is that I am asking for. Have you ever played the games where a character is sliding one way and when you try and change the characters direction it is not immediate as they need to slow down in the initial direction before they can start sliding the other way? The new game on the App Store 'Swing Copters' by the maker of Flappy Bird is exactly the effect I am talking about. Can someone please help me create this effect in SpriteKit. I have already tried achieving it by applying different forces but I am either not doing it correctly or the effect isn't possible with forces.
Thanks in advance!
Maybe you want to try working with some acceleration-stuff.
Let's think about the gravity on the earth (a = 9.81 metres/s²). If you throw a ball straight to the sky, the Ball is starting with a velocity of: lets say 5metres per second(positive velocity).
After a short time, the gravity is pulling the velocity of the ball down to 0, so the ball can't get any higher. Right after this, the gravity pulls the ball down until it hits the ground. (Negative velocity)
If we're talking about this in a game, where the ball doesn't move up or down but from left to right, you can use something like this. The moment when you throw the ball, is the moment in the game where you send the command to change the direction. The ball keeps going in the direction where it used to go, gets slower, stops, changes the direction and finally gets faster and faster until you send another command to change the direction again(Or it hits the Wall/the ground). In that case you have to inverse the acceleration you want to use, so the whole thing repeats in the other way.
If the ball should move to the right, positive acceleration,
if the ball should move to the left, negative acceleration.
As formula you can use something like
v = (int) (a * t + v0);
v0 = v;
v is the next velocity, a is the acceleration you want to use, t is the spent time and v0 is the current velocity. t should count the nano-time since the last direction-change. (int) casts the whole thing to an integer, so you can use this directly to move the ball/graphics on the screen.
Repeat this each frame.
For the direction change you can use
t = 0;
a = a * (-1);
t has to be 0 again, otherwise it gets buggy.
I hope this was helpful.

Resources