I'm trying to have a black hole like physics that will attract any object that will go close to it, then put it into the black hole orbit and like a vortex make it go to then center and disappear.
I ended up with something like this but doesn't work
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[DisallowMultipleComponent]
[ExecuteInEditMode]
[RequireComponent(typeof(CircleCollider2D))]
[RequireComponent(typeof(SpriteRenderer))]
public class BlackHole : MonoBehaviour
{
/// <summary> </summary>
public const float GRAVITY_PULL = 7000.0f;
/// <summary> </summary>
private const float SWIRLSTRENGTH = 5f;
// ------------------------------------------------
/// <summary> </summary>
private float _gravityRadius = 7.0f;
/// <summary> </summary>
private List<Rigidbody2D> _rigidBodies = new List<Rigidbody2D>();
// ------------------------------------------------
#if UNITY_EDITOR
void Update()
{
if( Application.isPlaying == false )
{
_gravityRadius =
GetComponent<CircleCollider2D>().radius;
}
}
#endif
private void LateUpdate()
{
UpdateBlackHole();
}
/// <summary>
/// Attract objects towards an area when they come within the bounds of a collider.
/// This function is on the physics timer so it won't necessarily run every frame.
/// </summary>
/// <param name="in_other">Any object within reach of gravity's collider</param>
void OnTriggerEnter2D(
Collider2D in_other
)
{
if ( in_other.attachedRigidbody != null
&& _rigidBodies != null )
{
//to get them nice and swirly, use the perpendicular to the direction to the vortex
Vector3 direction =
transform.position - in_other.attachedRigidbody.transform.position;
var tangent =
Vector3.Cross(direction, Vector3.forward).normalized * SWIRLSTRENGTH;
in_other.attachedRigidbody.velocity =
tangent;
_rigidBodies.Add( in_other.attachedRigidbody );
}
}
private void UpdateBlackHole()
{
if( _rigidBodies != null )
{
for (int i = 0; i < _rigidBodies.Count; i++)
{
if( _rigidBodies[i] != null )
{
CalculateMovement( _rigidBodies[i] );
}
}
}
}
private void CalculateMovement(
Rigidbody2D in_rb
)
{
float distance =
Vector3.Distance(
transform.position,
in_rb.transform.position
);
float gravityIntensity =
distance
/ _gravityRadius;
in_rb.AddForce(
(transform.position - in_rb.transform.position)
* gravityIntensity
* in_rb.mass
* GRAVITY_PULL
* Time.deltaTime);
in_rb.drag += 0.0001f;
Debug.DrawRay(
in_rb.transform.position,
transform.position - in_rb.transform.position
);
if( distance <= 0.1f )
{
_rigidBodies.Remove( in_rb );
Destroy( in_rb.gameObject );
}
}
}
this will make the object go up and down from the center of the black hole and increase it's speed that is something that I want but instead to go up and down I want to make it orbit around it and then get close to the center of the black hole during time.
any help?
Update 1: by adding a small force at the start I was able to make it rotate around the black hole, but it will not fall to the center of it
Update 2 :solved it by adding some drag, if someone is trying to achieve the same things feel free to use this script.
you need to give the object some start force because that will give horizontal speed and make an orbit. To make it spiral inward, make the start force very small and it will fall towards the black hole with some amount of horizontal speed.
Related
I'm developing game like Hitman Go , and I need to find which waypoints are closest to my target(specific waypoint ) when enemy has alerted by rock or sound and etc.
I set some point for enemy and My enemy patrolling between waypoints ( 8 -> 6 -> 1-> 2-> 3-> 4-> 5 ) then reveres his path.
so, when I throw rock in waypoint number 18, I need to move enemy to this waypoint, but with closest way. imaging enemy can be any this waypoint when he get aleret ( 8,6,1,2,3,4,5 points).
Note 1: The distance between two points is same.
Note2: My game is in 3d not 2d.
I use this code to move my enemy step by step ( turn base ).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WaypointController : MonoBehaviour
{
public List<Transform> waypoints = new List<Transform>();
private Transform targetWaypoint;
private int targetWaypointIndex = 0;
private float minDistance = 0.1f;
private int lastWaypointIndex;
public bool reversePath;
// what easetype to use for iTweening
public iTween.EaseType easeType = iTween.EaseType.easeInOutExpo;
// how fast we move
public float moveSpeed = 1.5f;
// time to rotate to face destination
public float rotateTime = 0.5f;
// delay to use before any call to iTween
public float iTweenDelay = 0f;
// Use this for initialization
void Start()
{
lastWaypointIndex = waypoints.Count - 1;
targetWaypoint = waypoints[targetWaypointIndex];
}
public void EnemyTurn()
{
float distance = Vector3.Distance(transform.position, targetWaypoint.position);
CheckDistanceToWaypoint(distance);
// move toward the destinationPos using the easeType and moveSpeed variables
iTween.MoveTo(gameObject, iTween.Hash(
"x", targetWaypoint.position.x,
"y", targetWaypoint.position.y,
"z", targetWaypoint.position.z,
"delay", iTweenDelay,
"easetype", easeType,
"speed", moveSpeed
));
}
void CheckDistanceToWaypoint(float currentDistance)
{
if (currentDistance <= minDistance)
{
targetWaypointIndex++;
UpdateTargetWaypoint();
}
}
void UpdateTargetWaypoint()
{
if (targetWaypointIndex > lastWaypointIndex)
{
if (reversePath)
{
waypoints.Reverse();
}
targetWaypointIndex = 1;
}
targetWaypoint = waypoints[targetWaypointIndex];
}
}
Since you asked in the comments for a non-A* solution & I was bored :)
Naive DFS pathfinder with very simple pruning.
Brute force and very wasteful both memory & CPU wise.
For a game similar to Hitman Go / Lara Croft Go - I would use this code and not a navmesh / A*.
For a RTS / FPS or any AI intensive games, I would definitely not use this solution.
public class GridPathfinder
{
// Not thread safe
private int? _currentShortestPath;
/// <summary>
/// Finds shortest path from cell A to B
/// </summary>
/// <returns>Shortest found path; null if found no path.</returns>
public IList<Node> GetShortestPath(Node a, Node b)
{
_currentShortestPath = null;
return GetShortestPathInternal(a, b, new List<Node>());
}
private IList<Node> GetShortestPathInternal(Node #from, Node to, List<Node> currentPath)
{
// Sanity
if (currentPath.Contains(from))
{
return null;
}
// Prune
if (_currentShortestPath.HasValue && currentPath.Count + 1 >= _currentShortestPath)
{
return null;
}
currentPath.Add(from);
if (from == to)
{
return currentPath;
}
// Check neighbors recursively
IList<Node> foundShortestPath = null;
foreach (var connectedCell in from.ConnectedCells)
{
var cellPath = GetShortestPathInternal(connectedCell, to, new List<Node>(currentPath));
if (cellPath == null || foundShortestPath != null && cellPath.Count >= foundShortestPath.Count)
{
continue;
}
foundShortestPath = cellPath;
}
// Update shortest path for future pruning
if (foundShortestPath != null && (!_currentShortestPath.HasValue || _currentShortestPath > foundShortestPath.Count))
{
_currentShortestPath = foundShortestPath.Count;
}
return foundShortestPath;
}
}
public class Node
{
private readonly HashSet<Node> _connectedCells = new HashSet<Node>();
public IEnumerable<Node> ConnectedCells => _connectedCells;
/// <summary>
/// Add a connection
/// </summary>
/// <param name="toAdd">Node to add</param>
/// <param name="isTwoWay">Should add a connection from target node to this node</param>
public void AddConnection(Node toAdd, bool isTwoWay=true)
{
if (toAdd == null || toAdd == this)
{
throw new Exception("Invalid connection attempted");
}
// Attempt to add
if (!_connectedCells.Add(toAdd))
{
return;
}
if (!isTwoWay) return;
toAdd.AddConnection(this);
}
}
I am trying to build a VR app for Oculus go. I am trying to move OVRPlayerContoller by pointing at a position on the ground, clicking to set a target position and then your character moves towards it. The player controller does not move towards the pointed position even tho the object is created on that position.I have written this script for it and attached and attached it to OVRPlayerController.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClickToMove : MonoBehaviour
{
private Vector3 targetPos; //This Vector3 will store the position where we click to move.
private bool Moving = false; //This bool keeps track of whether we are in the process of moving or not.
private GameObject targetInstance;
//The variables we want to customize. Added info headers to these for the Unity Editor.
[Header("Our Go controller object")]
public GameObject goController;
[Header("Movement Speed")]
public float speed = 1;
[Header("Stop When This Far Away From Target")]
public float haltDistance = 0;
[Header("Optional Target Object")]
public GameObject targetObj;
void Update()
{
MoveToTarget(); //Here we simply run our MoveToTarget method in the Update method.
//That way we don't clutter up the Update method with too much code.
}
void MoveToTarget() //Here we do the cluttering instead.
{
var ray = new Ray(goController.transform.position, goController.transform.forward); //Create a ray going from the goController position and in the Forward direction of the goController.
RaycastHit hitInfo; //Store info about what the ray hits.
Physics.Raycast(ray, out hitInfo, 100);
if (OVRInput.GetUp(OVRInput.Button.PrimaryIndexTrigger)) //If we release the trigger..
{
targetPos = hitInfo.point; //Make our targetPos assume the positional value of the hit point.
if (targetObj) //If we have specified a Target Object to mark where we click.
//If we didn't, then we don't want to try to instantiate it.
{
if (targetInstance) //If there is already a Target Object in the scene.
{
Destroy(targetInstance); //Destroy it.
}
targetInstance = Instantiate(targetObj, targetPos, transform.rotation); //Create our Target object at the position we clicked.
}
Moving = true; //And finally we set Moving to True.
}
if (Moving == true) //Since Moving is now true
{
transform.position = Vector3.MoveTowards(transform.position, new Vector3(targetPos.x, transform.position.y, targetPos.z), speed * Time.deltaTime); //Transform our x and z position to move towards the targetPos.
//Note that our y position is kept at default transform position since we only want to move along the ground plane.
}
if (Vector3.Distance(transform.position, targetPos) <= haltDistance + 1) //Check proximity to targetPos. Mainly useful to keep your player from setting a target position right next to say a building and then end up clipping through half of it.
{
if (targetInstance) //If we created a Target Object..
{
Destroy(targetInstance); //Then we want to destroy it when we reach it.
}
Moving = false; //Since we have now arrived at our target destination.
}
}
}
I created a cube prefab for the Target Object and Dragged the TrackedRemote Prefab(which contains Go controller model and script) onto the Go Contoller slot.
Then I created a ray from my controller using the script below and attached it to OVRCameraRig.
using UnityEngine;
using UnityEngine.Events;
public class VRRaycaster : MonoBehaviour
{
[System.Serializable]
public class Callback : UnityEvent<Ray, RaycastHit> { }
public Transform leftHandAnchor = null;
public Transform rightHandAnchor = null;
public Transform centerEyeAnchor = null;
public LineRenderer lineRenderer = null;
public float maxRayDistance = 500.0f;
public LayerMask excludeLayers;
public VRRaycaster.Callback raycastHitCallback;
void Awake()
{
if (leftHandAnchor == null)
{
Debug.LogWarning("Assign LeftHandAnchor in the inspector!");
GameObject left = GameObject.Find("LeftHandAnchor");
if (left != null)
{
leftHandAnchor = left.transform;
}
}
if (rightHandAnchor == null)
{
Debug.LogWarning("Assign RightHandAnchor in the inspector!");
GameObject right = GameObject.Find("RightHandAnchor");
if (right != null)
{
rightHandAnchor = right.transform;
}
}
if (centerEyeAnchor == null)
{
Debug.LogWarning("Assign CenterEyeAnchor in the inspector!");
GameObject center = GameObject.Find("CenterEyeAnchor");
if (center != null)
{
centerEyeAnchor = center.transform;
}
}
if (lineRenderer == null)
{
Debug.LogWarning("Assign a line renderer in the inspector!");
lineRenderer = gameObject.AddComponent<LineRenderer>();
lineRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
lineRenderer.receiveShadows = false;
lineRenderer.widthMultiplier = 0.02f;
}
}
Transform Pointer
{
get
{
OVRInput.Controller controller = OVRInput.GetConnectedControllers();
if ((controller & OVRInput.Controller.LTrackedRemote) != OVRInput.Controller.None)
{
return leftHandAnchor;
}
else if ((controller & OVRInput.Controller.RTrackedRemote) != OVRInput.Controller.None)
{
return rightHandAnchor;
}
// If no controllers are connected, we use ray from the view camera.
// This looks super ackward! Should probably fall back to a simple reticle!
return centerEyeAnchor;
}
}
void Update()
{
Transform pointer = Pointer;
if (pointer == null)
{
return;
}
Ray laserPointer = new Ray(pointer.position, pointer.forward);
if (lineRenderer != null)
{
lineRenderer.SetPosition(0, laserPointer.origin);
lineRenderer.SetPosition(1, laserPointer.origin + laserPointer.direction * maxRayDistance);
}
RaycastHit hit;
if (Physics.Raycast(laserPointer, out hit, maxRayDistance, ~excludeLayers))
{
if (lineRenderer != null)
{
lineRenderer.SetPosition(1, hit.point);
}
if (raycastHitCallback != null)
{
raycastHitCallback.Invoke(laserPointer, hit);
}
}
}
}
The problem is that when I press the trigger, the GameObject is created at that point on the floor but the OVRPlayerController does not move towards it.
I have also attached my OVRPlayerController.cs script below:
using System;
using UnityEngine;
/// <summary>
/// Controls the player's movement in virtual reality.
/// </summary>
[RequireComponent(typeof(CharacterController))]
public class OVRPlayerController : MonoBehaviour
{
/// <summary>
/// The rate acceleration during movement.
/// </summary>
public float Acceleration = 0.1f;
/// <summary>
/// The rate of damping on movement.
/// </summary>
public float Damping = 0.3f;
/// <summary>
/// The rate of additional damping when moving sideways or backwards.
/// </summary>
public float BackAndSideDampen = 0.5f;
/// <summary>
/// The force applied to the character when jumping.
/// </summary>
public float JumpForce = 0.3f;
/// <summary>
/// The rate of rotation when using a gamepad.
/// </summary>
public float RotationAmount = 1.5f;
/// <summary>
/// The rate of rotation when using the keyboard.
/// </summary>
public float RotationRatchet = 45.0f;
/// <summary>
/// The player will rotate in fixed steps if Snap Rotation is enabled.
/// </summary>
[Tooltip("The player will rotate in fixed steps if Snap Rotation is enabled.")]
public bool SnapRotation = true;
/// <summary>
/// How many fixed speeds to use with linear movement? 0=linear control
/// </summary>
[Tooltip("How many fixed speeds to use with linear movement? 0=linear control")]
public int FixedSpeedSteps;
/// <summary>
/// If true, reset the initial yaw of the player controller when the Hmd pose is recentered.
/// </summary>
public bool HmdResetsY = true;
/// <summary>
/// If true, tracking data from a child OVRCameraRig will update the direction of movement.
/// </summary>
public bool HmdRotatesY = true;
/// <summary>
/// Modifies the strength of gravity.
/// </summary>
public float GravityModifier = 0.379f;
/// <summary>
/// If true, each OVRPlayerController will use the player's physical height.
/// </summary>
public bool useProfileData = true;
/// <summary>
/// The CameraHeight is the actual height of the HMD and can be used to adjust the height of the character controller, which will affect the
/// ability of the character to move into areas with a low ceiling.
/// </summary>
[NonSerialized]
public float CameraHeight;
/// <summary>
/// This event is raised after the character controller is moved. This is used by the OVRAvatarLocomotion script to keep the avatar transform synchronized
/// with the OVRPlayerController.
/// </summary>
public event Action<Transform> TransformUpdated;
/// <summary>
/// This bool is set to true whenever the player controller has been teleported. It is reset after every frame. Some systems, such as
/// CharacterCameraConstraint, test this boolean in order to disable logic that moves the character controller immediately
/// following the teleport.
/// </summary>
[NonSerialized] // This doesn't need to be visible in the inspector.
public bool Teleported;
/// <summary>
/// This event is raised immediately after the camera transform has been updated, but before movement is updated.
/// </summary>
public event Action CameraUpdated;
/// <summary>
/// This event is raised right before the character controller is actually moved in order to provide other systems the opportunity to
/// move the character controller in response to things other than user input, such as movement of the HMD. See CharacterCameraConstraint.cs
/// for an example of this.
/// </summary>
public event Action PreCharacterMove;
/// <summary>
/// When true, user input will be applied to linear movement. Set this to false whenever the player controller needs to ignore input for
/// linear movement.
/// </summary>
public bool EnableLinearMovement = true;
/// <summary>
/// When true, user input will be applied to rotation. Set this to false whenever the player controller needs to ignore input for rotation.
/// </summary>
public bool EnableRotation = true;
protected CharacterController Controller = null;
protected OVRCameraRig CameraRig = null;
private float MoveScale = 1.0f;
private Vector3 MoveThrottle = Vector3.zero;
private float FallSpeed = 0.0f;
private OVRPose? InitialPose;
public float InitialYRotation { get; private set; }
private float MoveScaleMultiplier = 1.0f;
private float RotationScaleMultiplier = 1.0f;
private bool SkipMouseRotation = true; // It is rare to want to use mouse movement in VR, so ignore the mouse by default.
private bool HaltUpdateMovement = false;
private bool prevHatLeft = false;
private bool prevHatRight = false;
private float SimulationRate = 60f;
private float buttonRotation = 0f;
private bool ReadyToSnapTurn; // Set to true when a snap turn has occurred, code requires one frame of centered thumbstick to enable another snap turn.
void Start()
{
// Add eye-depth as a camera offset from the player controller
var p = CameraRig.transform.localPosition;
p.z = OVRManager.profile.eyeDepth;
CameraRig.transform.localPosition = p;
}
void Awake()
{
Controller = gameObject.GetComponent<CharacterController>();
if (Controller == null)
Debug.LogWarning("OVRPlayerController: No CharacterController attached.");
// We use OVRCameraRig to set rotations to cameras,
// and to be influenced by rotation
OVRCameraRig[] CameraRigs = gameObject.GetComponentsInChildren<OVRCameraRig>();
if (CameraRigs.Length == 0)
Debug.LogWarning("OVRPlayerController: No OVRCameraRig attached.");
else if (CameraRigs.Length > 1)
Debug.LogWarning("OVRPlayerController: More then 1 OVRCameraRig attached.");
else
CameraRig = CameraRigs[0];
InitialYRotation = transform.rotation.eulerAngles.y;
}
void OnEnable()
{
OVRManager.display.RecenteredPose += ResetOrientation;
if (CameraRig != null)
{
CameraRig.UpdatedAnchors += UpdateTransform;
}
}
void OnDisable()
{
OVRManager.display.RecenteredPose -= ResetOrientation;
if (CameraRig != null)
{
CameraRig.UpdatedAnchors -= UpdateTransform;
}
}
void Update()
{
//Use keys to ratchet rotation
if (Input.GetKeyDown(KeyCode.Q))
buttonRotation -= RotationRatchet;
if (Input.GetKeyDown(KeyCode.E))
buttonRotation += RotationRatchet;
}
protected virtual void UpdateController()
{
if (useProfileData)
{
if (InitialPose == null)
{
// Save the initial pose so it can be recovered if useProfileData
// is turned off later.
InitialPose = new OVRPose()
{
position = CameraRig.transform.localPosition,
orientation = CameraRig.transform.localRotation
};
}
var p = CameraRig.transform.localPosition;
if (OVRManager.instance.trackingOriginType == OVRManager.TrackingOrigin.EyeLevel)
{
p.y = OVRManager.profile.eyeHeight - (0.5f * Controller.height) + Controller.center.y;
}
else if (OVRManager.instance.trackingOriginType == OVRManager.TrackingOrigin.FloorLevel)
{
p.y = -(0.5f * Controller.height) + Controller.center.y;
}
CameraRig.transform.localPosition = p;
}
else if (InitialPose != null)
{
// Return to the initial pose if useProfileData was turned off at runtime
CameraRig.transform.localPosition = InitialPose.Value.position;
CameraRig.transform.localRotation = InitialPose.Value.orientation;
InitialPose = null;
}
CameraHeight = CameraRig.centerEyeAnchor.localPosition.y;
if (CameraUpdated != null)
{
CameraUpdated();
}
UpdateMovement();
Vector3 moveDirection = Vector3.zero;
float motorDamp = (1.0f + (Damping * SimulationRate * Time.deltaTime));
MoveThrottle.x /= motorDamp;
MoveThrottle.y = (MoveThrottle.y > 0.0f) ? (MoveThrottle.y / motorDamp) : MoveThrottle.y;
MoveThrottle.z /= motorDamp;
moveDirection += MoveThrottle * SimulationRate * Time.deltaTime;
// Gravity
if (Controller.isGrounded && FallSpeed <= 0)
FallSpeed = ((Physics.gravity.y * (GravityModifier * 0.002f)));
else
FallSpeed += ((Physics.gravity.y * (GravityModifier * 0.002f)) * SimulationRate * Time.deltaTime);
moveDirection.y += FallSpeed * SimulationRate * Time.deltaTime;
if (Controller.isGrounded && MoveThrottle.y <= transform.lossyScale.y * 0.001f)
{
// Offset correction for uneven ground
float bumpUpOffset = Mathf.Max(Controller.stepOffset, new Vector3(moveDirection.x, 0, moveDirection.z).magnitude);
moveDirection -= bumpUpOffset * Vector3.up;
}
if (PreCharacterMove != null)
{
PreCharacterMove();
Teleported = false;
}
Vector3 predictedXZ = Vector3.Scale((Controller.transform.localPosition + moveDirection), new Vector3(1, 0, 1));
// Move contoller
Controller.Move(moveDirection);
Vector3 actualXZ = Vector3.Scale(Controller.transform.localPosition, new Vector3(1, 0, 1));
if (predictedXZ != actualXZ)
MoveThrottle += (actualXZ - predictedXZ) / (SimulationRate * Time.deltaTime);
}
public virtual void UpdateMovement()
{
if (HaltUpdateMovement)
return;
if (EnableLinearMovement)
{
bool moveForward = Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow);
bool moveLeft = Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow);
bool moveRight = Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow);
bool moveBack = Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow);
bool dpad_move = false;
if (OVRInput.Get(OVRInput.Button.DpadUp))
{
moveForward = true;
dpad_move = true;
}
if (OVRInput.Get(OVRInput.Button.DpadDown))
{
moveBack = true;
dpad_move = true;
}
MoveScale = 1.0f;
if ((moveForward && moveLeft) || (moveForward && moveRight) ||
(moveBack && moveLeft) || (moveBack && moveRight))
MoveScale = 0.70710678f;
// No positional movement if we are in the air
if (!Controller.isGrounded)
MoveScale = 0.0f;
MoveScale *= SimulationRate * Time.deltaTime;
// Compute this for key movement
float moveInfluence = Acceleration * 0.1f * MoveScale * MoveScaleMultiplier;
// Run!
if (dpad_move || Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
moveInfluence *= 2.0f;
Quaternion ort = transform.rotation;
Vector3 ortEuler = ort.eulerAngles;
ortEuler.z = ortEuler.x = 0f;
ort = Quaternion.Euler(ortEuler);
if (moveForward)
MoveThrottle += ort * (transform.lossyScale.z * moveInfluence * Vector3.forward);
if (moveBack)
MoveThrottle += ort * (transform.lossyScale.z * moveInfluence * BackAndSideDampen * Vector3.back);
if (moveLeft)
MoveThrottle += ort * (transform.lossyScale.x * moveInfluence * BackAndSideDampen * Vector3.left);
if (moveRight)
MoveThrottle += ort * (transform.lossyScale.x * moveInfluence * BackAndSideDampen * Vector3.right);
moveInfluence = Acceleration * 0.1f * MoveScale * MoveScaleMultiplier;
#if !UNITY_ANDROID // LeftTrigger not avail on Android game pad
moveInfluence *= 1.0f + OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger);
#endif
Vector2 primaryAxis = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick);
// If speed quantization is enabled, adjust the input to the number of fixed speed steps.
if (FixedSpeedSteps > 0)
{
primaryAxis.y = Mathf.Round(primaryAxis.y * FixedSpeedSteps) / FixedSpeedSteps;
primaryAxis.x = Mathf.Round(primaryAxis.x * FixedSpeedSteps) / FixedSpeedSteps;
}
if (primaryAxis.y > 0.0f)
MoveThrottle += ort * (primaryAxis.y * transform.lossyScale.z * moveInfluence * Vector3.forward);
if (primaryAxis.y < 0.0f)
MoveThrottle += ort * (Mathf.Abs(primaryAxis.y) * transform.lossyScale.z * moveInfluence *
BackAndSideDampen * Vector3.back);
if (primaryAxis.x < 0.0f)
MoveThrottle += ort * (Mathf.Abs(primaryAxis.x) * transform.lossyScale.x * moveInfluence *
BackAndSideDampen * Vector3.left);
if (primaryAxis.x > 0.0f)
MoveThrottle += ort * (primaryAxis.x * transform.lossyScale.x * moveInfluence * BackAndSideDampen *
Vector3.right);
}
if (EnableRotation)
{
Vector3 euler = transform.rotation.eulerAngles;
float rotateInfluence = SimulationRate * Time.deltaTime * RotationAmount * RotationScaleMultiplier;
bool curHatLeft = OVRInput.Get(OVRInput.Button.PrimaryShoulder);
if (curHatLeft && !prevHatLeft)
euler.y -= RotationRatchet;
prevHatLeft = curHatLeft;
bool curHatRight = OVRInput.Get(OVRInput.Button.SecondaryShoulder);
if (curHatRight && !prevHatRight)
euler.y += RotationRatchet;
prevHatRight = curHatRight;
euler.y += buttonRotation;
buttonRotation = 0f;
#if !UNITY_ANDROID || UNITY_EDITOR
if (!SkipMouseRotation)
euler.y += Input.GetAxis("Mouse X") * rotateInfluence * 3.25f;
#endif
if (SnapRotation)
{
if (OVRInput.Get(OVRInput.Button.SecondaryThumbstickLeft))
{
if (ReadyToSnapTurn)
{
euler.y -= RotationRatchet;
ReadyToSnapTurn = false;
}
}
else if (OVRInput.Get(OVRInput.Button.SecondaryThumbstickRight))
{
if (ReadyToSnapTurn)
{
euler.y += RotationRatchet;
ReadyToSnapTurn = false;
}
}
else
{
ReadyToSnapTurn = true;
}
}
else
{
Vector2 secondaryAxis = OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick);
euler.y += secondaryAxis.x * rotateInfluence;
}
transform.rotation = Quaternion.Euler(euler);
}
}
/// <summary>
/// Invoked by OVRCameraRig's UpdatedAnchors callback. Allows the Hmd rotation to update the facing direction of the player.
/// </summary>
public void UpdateTransform(OVRCameraRig rig)
{
Transform root = CameraRig.trackingSpace;
Transform centerEye = CameraRig.centerEyeAnchor;
if (HmdRotatesY && !Teleported)
{
Vector3 prevPos = root.position;
Quaternion prevRot = root.rotation;
transform.rotation = Quaternion.Euler(0.0f, centerEye.rotation.eulerAngles.y, 0.0f);
root.position = prevPos;
root.rotation = prevRot;
}
UpdateController();
if (TransformUpdated != null)
{
TransformUpdated(root);
}
}
/// <summary>
/// Jump! Must be enabled manually.
/// </summary>
public bool Jump()
{
if (!Controller.isGrounded)
return false;
MoveThrottle += new Vector3(0, transform.lossyScale.y * JumpForce, 0);
return true;
}
/// <summary>
/// Stop this instance.
/// </summary>
public void Stop()
{
Controller.Move(Vector3.zero);
MoveThrottle = Vector3.zero;
FallSpeed = 0.0f;
}
/// <summary>
/// Gets the move scale multiplier.
/// </summary>
/// <param name="moveScaleMultiplier">Move scale multiplier.</param>
public void GetMoveScaleMultiplier(ref float moveScaleMultiplier)
{
moveScaleMultiplier = MoveScaleMultiplier;
}
/// <summary>
/// Sets the move scale multiplier.
/// </summary>
/// <param name="moveScaleMultiplier">Move scale multiplier.</param>
public void SetMoveScaleMultiplier(float moveScaleMultiplier)
{
MoveScaleMultiplier = moveScaleMultiplier;
}
/// <summary>
/// Gets the rotation scale multiplier.
/// </summary>
/// <param name="rotationScaleMultiplier">Rotation scale multiplier.</param>
public void GetRotationScaleMultiplier(ref float rotationScaleMultiplier)
{
rotationScaleMultiplier = RotationScaleMultiplier;
}
/// <summary>
/// Sets the rotation scale multiplier.
/// </summary>
/// <param name="rotationScaleMultiplier">Rotation scale multiplier.</param>
public void SetRotationScaleMultiplier(float rotationScaleMultiplier)
{
RotationScaleMultiplier = rotationScaleMultiplier;
}
/// <summary>
/// Gets the allow mouse rotation.
/// </summary>
/// <param name="skipMouseRotation">Allow mouse rotation.</param>
public void GetSkipMouseRotation(ref bool skipMouseRotation)
{
skipMouseRotation = SkipMouseRotation;
}
/// <summary>
/// Sets the allow mouse rotation.
/// </summary>
/// <param name="skipMouseRotation">If set to <c>true</c> allow mouse rotation.</param>
public void SetSkipMouseRotation(bool skipMouseRotation)
{
SkipMouseRotation = skipMouseRotation;
}
/// <summary>
/// Gets the halt update movement.
/// </summary>
/// <param name="haltUpdateMovement">Halt update movement.</param>
public void GetHaltUpdateMovement(ref bool haltUpdateMovement)
{
haltUpdateMovement = HaltUpdateMovement;
}
/// <summary>
/// Sets the halt update movement.
/// </summary>
/// <param name="haltUpdateMovement">If set to <c>true</c> halt update movement.</param>
public void SetHaltUpdateMovement(bool haltUpdateMovement)
{
HaltUpdateMovement = haltUpdateMovement;
}
/// <summary>
/// Resets the player look rotation when the device orientation is reset.
/// </summary>
public void ResetOrientation()
{
if (HmdResetsY && !HmdRotatesY)
{
Vector3 euler = transform.rotation.eulerAngles;
euler.y = InitialYRotation;
transform.rotation = Quaternion.Euler(euler);
}
}
}
I'm making a simple project in Unity where there is a Ball attached to a SpringJoint2d component the ball is on an angled slope, like in the image below:
I simply want the user to be able to drag the ball backward along the edge of the slope only,in other words I don't want the user to be able to move the ball away from the slope or into it.
I'v been trying several ways I thought could do the job hers the script of the dragging with what I tried:
(This Is the updated version)
public class ball : MonoBehaviour
{
public Rigidbody2D rb;
public Transform spring;
public Transform calcpoint;
private Vector3 start;
private Vector3 end;
private bool isPressed = false;
RaycastHit2D[] hits = new RaycastHit2D[2];
RaycastHit2D[] hits2 = new RaycastHit2D[2];
float factor = 0;
private void OnMouseDown()
{
if (!isPressed)
{
isPressed = true;
rb.isKinematic = true;
}
}
private void OnMouseUp()
{
isPressed = false;
rb.isKinematic = false;
StartCoroutine(release());
}
/// <summary>
/// release the ball from the spring joint after a small amount of time
/// </summary>
/// <returns></returns>
IEnumerator release()
{
yield return new WaitForSeconds(0.1f);
rb.GetComponent<SpringJoint2D>().enabled = false;
}
// Update is called once per frame
void Update()
{
if (isPressed)
{
if (Vector3.Distance(spring.position, rb.position) > 3f || spring.position.x < (rb.position.x - 1)) return;//restrict the dragging of the ball to not go beyond the spring point and not too far back
float angle = 0;
if (checkGround() > 1)//if we hit the slope with the ray cast downward from the mouse/Tap position
{
angle = Mathf.Abs(Mathf.Atan2(hits[1].normal.x, hits[1].normal.y) * Mathf.Rad2Deg); //get angle
factor = (float)(((45 - angle) * 0.02) + 1) * (angle / 45);//an inaccurate formula to offset the ball to be on top of the slope that works just fine with some glitches
rb.position = hits[1].point + new Vector2(0, factor * 1f);//position the ball at the point were the ray cast downward from the mouse hit
//(that puts the ball center on the line of the slope) so I offset it usinf the formula above
}
}
}
private int checkGround()
{
int h = Physics2D.RaycastNonAlloc(Camera.main.ScreenToWorldPoint(Input.mousePosition), -Vector2.up, hits); //cast downwards
return h;
}
}
here are the settings on the ball:
and the slope setup:
The dragging of the ball works fine ,at one point the player could drag it in the air or into the slope, I managed to fix that with the new code so now the player could only drag it on the edge, though my calculations are still a bit flawed and when the slopes angle is changed the ball would dip a bit inside the slope and that causes some problems at release.
The method used to try to solve the problem is simple, when the player start dragging the ball I cast a ray from the mouse downward and pit the ball on the point of impact with the slope ,offsetting it to sit on top of it,right ow the problem is that the offsetting part is not accurate enough.
I hope I explained myself a bit better this time Thanks:)
After lots of trial and error I did manage to come up with a perfect solution to the problem so I thought I might as well share the answer maybe it will help someone.
here is the updated code I changed my method of restricting the movement completely now I use simple linear line equation as shown below:
private void OnMouseDown()
{
if (!isPressed)
{
//cast a ray on the slope
if (checkGround() > 1)
{
angle = Mathf.Abs(Mathf.Atan2(hits[1].normal.x, hits[1].normal.y) * Mathf.Rad2Deg); //get angle
slope = Mathf.Tan(angle * Mathf.Deg2Rad);//get the slope steepiness
}
isPressed = true;
rb.isKinematic = true;
}
}
private void OnMouseUp()
{
isPressed = false;
rb.isKinematic = false;
StartCoroutine(release());
}
void Update() {
if (isPressed)
{
xMove = Camera.main.ScreenToWorldPoint(Input.mousePosition).x - spring.position.x;//get how much the mouse moved backward or forward
if (xMove < -3f ) xMove = -3f; //restrict the drag range to 3 backward
if (xMove > 0.3f) xMove = 0.3f;//restrict the drag range to 0.3 forward
xpos = spring.position.x+xMove;//since the ball and the spring start at exactly the same position the new ball's x position would be the spring x + the x movement we calculated above
ypos = (xMove * slope)- spring.position.y; //the y posistion would be y=mx+b so the the x movement * the slop steepiness - the starting y position
rb.position = new Vector2(xpos, -ypos);//set the new position of the ball
}
}
private int checkGround()
{
int h = Physics2D.RaycastNonAlloc(Camera.main.ScreenToWorldPoint(Input.mousePosition), -Vector2.up, hits); //cast downwards
return h;
}
I have created some moving platforms for my game. There's a game object called PlatformPath1 which has children that define the start and end of the platform's cycle and then obviously there's the actual platform which follows the path. The platform moves perfect however, like expected, the player does not move with the platform. How would I get the player to move with the platform?
Here is the code for PlatformPath1
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
public class FollowPath : MonoBehaviour
{
public enum FollowType
{
MoveTowards,
Lerp
}
public FollowType Type = FollowType.MoveTowards;
public PathDefinition Path;
public float Speed = 1;
public float MaxDistanceToGoal = .1f;
private IEnumerator<Transform> _currentPoint;
public void Start()
{
if (Path == null)
{
Debug.LogError("Path cannot be null", gameObject);
return;
}
_currentPoint = Path.GetPathEnumerator();
_currentPoint.MoveNext();
if (_currentPoint.Current == null)
return;
transform.position = _currentPoint.Current.position;
}
public void Update()
{
if (_currentPoint == null || _currentPoint.Current == null)
return;
if (Type == FollowType.MoveTowards)
transform.position = Vector3.MoveTowards (transform.position, _currentPoint.Current.position, Time.deltaTime * Speed);
else if (Type == FollowType.Lerp)
transform.position = Vector3.Lerp(transform.position, _currentPoint.Current.position, Time.deltaTime * Speed);
var distanceSquared = (transform.position - _currentPoint.Current.position).sqrMagnitude;
if (distanceSquared < MaxDistanceToGoal * MaxDistanceToGoal)
_currentPoint.MoveNext();
}
}
And here is the code for the platform
using System;
using UnityEngine;
using System.Collections.Generic;
using System.Collections;
public class PathDefinition : MonoBehaviour
{
public Transform[] Points;
public IEnumerator<Transform> GetPathEnumerator()
{
if(Points == null || Points.Length < 1)
yield break;
var direction = 1;
var index = 0;
while (true)
{
yield return Points[index];
if (Points.Length == 1)
continue;
if (index <= 0)
direction = 1;
else if (index >= Points.Length - 1)
direction = -1;
index = index + direction;
}
}
public void OnDrawGizmos()
{
if (Points == null || Points.Length < 2)
return;
for (var i = 1; i < Points.Length; i++) {
Gizmos.DrawLine (Points [i - 1].position, Points [i].position);
}
}
}
You could add the Player as a child to the platform. That way, when the platform moves, the player will too.
At the end of the movement (or on some user input), you could break the parenting. Here's some code you can try out.
public GameObject platform; //The platform Game Object
public GameObject player; //The player Game Object
//Call this to have the player parented to the platform.
//So, say for example, you have a trigger that the player steps on
//to activate the platform, you can call this method then
void AttachPlayerToPlatform () {
player.transform.parent = platform.transform;
}
//Use this method alternatively, if you wish to specify which
//platform the player Game Object needs to attach to (more useful)
void AttachPlayerToPlatform (GameObject platformToAttachTo) {
player.transform.parent = platformToAttachTo.transform;
}
//Call this to detach the player from the platform
//This can be used say at the end of the platform's movement
void DetachPlayerFromPlatform () {
player.transform.parent = null;
}
If you were to stand on a moving platform in the real world, the reason you would move with the platform is because of the friction between the platform and your feet. If the platform were covered in ice, you might not move with the platform if it begins its motion while you're on it!
Now we can implement this in your game's physics. Normally your friction might just slow your player down to zero speed when you're not trying to walk. Instead you can check the ground collider on impact to see if it has a moving platform script, and get the speed of the platform. Then use this speed as the "zero point" for your motion calculation.
I thought this was going to be difficult, but I actually found it really simple to make a solution that seems to work pretty well.
The character in my game has a Box Collider. It's not a trigger and it doesn't use a physics material. It has a Rigidbody with a Mass of 1, Drag of 0, Angular Drag of 0.05, Uses Gravity, is not Kinematic, does not Interpolate, and Collision Detection is Discrete. It has No Constraints. For lateral movement, I use transform.Translate and for jumping I use Rigidbody's AddForce with ForceMode.VelocityChange as the final argument.
The moving platform also has a Box Collider. I set the transform.position based on the results of a call to Vector3.Lerp on every frame. I also have this script on the moving platform:
void OnCollisionEnter(Collision collision) {
// Attach the object to this platform, but have them stay where they are in world space.
collision.transform.SetParent(transform, true);
Debug.Log("On platform.");
}
void OnCollisionExit(Collision collision) {
// Detach the object from this platform, but have them stay where they are in world space.
collision.transform.SetParent(transform.parent, true);
Debug.Log("Off platform.");
}
And that's all. Really, it's just two lines of code in the script to declare that I'm implementing the two methods, and then the actual implementation of each is a single line. All of the info at the start is just for in case the Collision Detection isn't actually working out in your project (I always forget what the rules are for what does and doesn't count as a collision and/or a trigger.)
This should be an easy task, and I have googled it, but I can't figure out why any of the examples are working for me.
Basically, I want to place tiles on the ground in my first person game. I want the object I want to place on the ground to "float" in mid-air while choosing the perfect location for it. I can instantiate the object, make it a child of the player camera, but I'm unable to position it X units in front of the camera; it always ends up "on" the player;
public void StartPlacing ( Item item ) {
Object itemPrefab = Resources.Load( "Prefabs/" + item.prefabName );
GameObject itemObject = (GameObject)Instantiate( itemPrefab );
itemObject.transform.parent = playerCamera.transform;
// What to do here to place it in front of the camera? I've tried this:
itemObject.localPosition = new Vector3( 0, 0, 5 );
}
UPDATE: The camera is a child of the player (Character Controller), and the camera is in perspective mode.
You could use the forward vector of the object, something like this:
public GameObject frontObject;
public float distance;
void Update () {
frontObject.transform.position = Camera.main.transform.position + Camera.main.transform.forward * distance;
}
Thanks for all the useful suggestions, everyone! I came up with the following code which suits my needs:
using UnityEngine;
using System.Collections;
public class ConstructionController : MonoBehaviour {
private Camera playerCamera;
private GameObject itemObject;
private float distance = 3.0f;
// Use this for initialization
void Start () {
playerCamera = GetComponentInChildren<Camera>();
}
// Update is called once per frame
void Update () {
if ( itemObject != null ) {
itemObject.transform.position = playerCamera.transform.position + playerCamera.transform.forward * distance;
itemObject.transform.rotation = new Quaternion( 0.0f, playerCamera.transform.rotation.y, 0.0f, playerCamera.transform.rotation.w );
}
}
// Start constructing an item
public void StartConstructingItem ( Item item ) {
Object itemPrefab = Resources.Load( "Prefabs/" + item.prefabName );
itemObject = (GameObject)Instantiate( itemPrefab );
}
}