I'm creating an Archery, Platformer, Shooting game named "ArcheryRun" with a small team. We have a powerbar (shown in orange) which increases as you hold down the "Left Mouse Button". However since its a UI element it is static in a position.
I would like it to appear above the player when they change their z-axis as Ive done with the Arrow Image by using a 2D Sprite object. However I can't seem how to change the z-axis of a UI Image relative to the player or use a Game Object which allows a fill option.
Any help is appreciated, thanks :)
Change Orange Powerbar to Follow Player
If we understand your question, this should work:
This method gives you screen canvas position from world position:
public static Vector3 GetScreenPositionFromWorldPosition(Vector3 targetPosition)
{
Vector3 screenPos;
screenPos = Camera.main.WorldToScreenPoint(targetPosition);
return new Vector3 (screenPos.x, screenPos.y, 0f);
}
Then you need a script on top of power bar, lets say like this:
public class PowerBar : MonoBehaviour
{
public Transform target;
RectTransform _rectTransform;
void Awake ()
{
_rectTransform = GetComponent<RectTransform> ();
}
public void updatePosition()
{
Vector3 pos = YourStaticClassWith.GetScreenPositionFromWorldPosition (target.position);
Vector2 rpos = pos;
_rectTransform.anchoredPosition3D = rpos + Vector2.up * 100f; // 100f is value of how many pixels above the target that UI element should apear
}
void LateUpdate()
{
updatePosition ();
}
}
The target is basicly transform of your player object.
The 100f value represents pixels above the target.
Related
so I have a moving game object and i want to visualize the direction of its velocity as an arrow ( vector ) ,
I could not find a function that enables me to show that vector in the scene !
Vector3 direction ;
and i'm stuck finding method to show this vector in the scene .
Suppose you're looking for a simple gizmo to visualise the velocity vector. In that case, you could use OnDrawGizmos() to draw it and then enable Gizmos within Game view using the Gizmos toggle located at the right-most of the window:
For the code itself, you could use Handles.ArrowHandleCap to visualise a Rigidbody's velocity as follows:
[RequireComponent(typeof(Rigidbody))]
public class VelocityVisualizer : MonoBehaviour
{
// The length of the arrow, in meters
[SerializeField] [Range(0.5F, 2)] private float arrowLength = 1.0F;
private Rigidbody _rigidbody;
private void Start()
{
_rigidbody = GetComponent<Rigidbody>();
}
private void OnDrawGizmos()
{
if (!Application.isPlaying) return;
var position = transform.position;
var velocity = _rigidbody.velocity;
if (velocity.magnitude < 0.1f) return;
Handles.color = Color.red;
Handles.ArrowHandleCap(0, position, Quaternion.LookRotation(velocity), arrowLength, EventType.Repaint);
}
}
Attach this script as a component of a game object that has a Rigidbody, and it will display its velocity direction using an arrow
I am making a 3D Planet roaming game. The Planet itself is 3D, but every object in the scene will be 2D. As the player walks around the planet, their rotation relative north changes, and thus, if objects are placed statically in the scene, sometimes objects will appear upside down. I basically want every object to be tangential to the sphere, while still maintaining its "uprightness".
Vector3 pos = transform.position;
Vector3 planetPos = Planet.transform.position;
Vector3 direction = (planetPos - pos).normalized; // Calculate Tangent
transform.rotation = Quaternion.Euler(direction);
transform.Rotate(new Vector3(90, 0, 0));
This code here rotates the object relative to the planet, but it doesnt maintain is orientation relative to the player.
How can I get the other objects to not appear upside down?
Spherical Billboarding
You could find the direction that the object was relative to the world, and make the object look at that.
public GameObject[] objs;
public Vector3 worldPos;
void Update()
{
foreach (GameObject obj in objs)
{
obj.transform.rotation = Quaternion.LookRotation(obj.transform.position - worldPos);
}
}
This disables physics, so you could add more:
public GameObject[] objs;
public Vector3 worldPos;
public gravityForce;
Vector3 gravity;
Quaternion look;
void Update()
{
foreach (GameObject obj in objs)
{
look = Quaternion.LookRotation(obj.transform.position - worldPos);
ChangeGravity(look, obj);
}
}
Rigidbody rb;
void ChangeGravity(Quaternion looking, GameObject obj)
{
gravity = new Vector3(looking.x, looking.y, looking.z);
gravity.Normalize();
gravity *= -gravityForce;
rb = obj.GetComponent<Rigidbody>();
rb.useGravity = false;
rb.AddForce(gravity);
}
These were untested, but the first one is much more likely to work.
I would like to calculate a new position based on the pitch of a mesh in order to make an object following the top of my object which is rotated:
And result in:
I cannot make the square object as represented above as a child (in the Unity object hierarchy) of the line object because the rotated object can see its scale changed at anytime.
Does a mathematics solution can be used in this case?
Hotspots
If you'd like to place something at a particular location on a generic object which can be scaled or transformed anywhere, then a "hotspot" can be particularly useful.
What's a hotspot?
Edit the target gameobject (the line in this case) and add an empty gameobject to it. Give it some appropriate name - "cross arms hotspot" for example, and then move it to the location where you'd like your other gameobject to target. Essentially, a hotspot is just an empty gameobject - a placement marker of sorts.
How do I use it?
All you need is a reference to the hotspot gameobject. You could do this by adding a little script to the pole gameobject which tracks it for you:
public class PowerPole : MonoBehaviour {
public GameObject CrossArmsHotspot; // Set this in the inspector
}
Then you can get that hotspot reference from any power pole instance like this:
var targetHotspot = aPowerPoleGameObject.GetComponent<PowerPole>().CrossArmsHotspot;
Then it's just a case of getting your target object to place itself where that hotspot is, using whichever technique you prefer. If you want it to just "stick" there, then:
void Start(){
targetHotspot = aPowerPoleGameObject.GetComponent<PowerPole>().CrossArmsHotspot;
}
void Update(){
transform.position = targetHotspot.transform.position;
}
would be a (simplfied) example.
A more advanced example using lerp to move towards the hotspot:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrossArmsMover : MonoBehaviour
{
public GameObject PowerPole;
private GameObject targetHotspot;
public GameObject CrossArms;
public float TimeToTake = 5f;
private float timeSoFar;
private Vector3 startPosition;
private Quaternion startRotation;
// Start is called before the first frame update
void Start()
{
startPosition = CrossArms.transform.position;
startRotation = CrossArms.transform.rotation;
targetHotspot = PowerPole.GetComponent<PowerPole>().CrossArmsHotspot;
}
// Update is called once per frame
void Update()
{
timeSoFar+=Time.deltaTime;
var progress = timeSoFar/TimeToTake;
// Clamp it so it doesn't go above 1.
if(progress > 1f){
progress = 1f;
}
// Target position / rotation is..
var targetPosition = targetHotspot.transform.position;
var targetRotation = targetHotspot.transform.rotation;
// Lerp towards that target transform:
CrossArms.transform.position = Vector3.Lerp(startPosition, targetPosition, progress);
CrossArms.transform.rotation = Quaternion.Lerp(startRotation, targetRotation, progress);
}
}
You would need to put a script on the following gameobject in wich you would put :
GameObject pitcher = //reference to the gameobject with the pitch;
const int DISTANCE_ON_LINE = //distance between the 2 objects
void Update() {
transform.position = pitcher.transform.position + pitcher.transform.forward * DISTANCE_ON_LINE;
}
With the Unity 5.1 and Oculus SDK 0.6 and the new built-in Virtual Reality Supported check-box, I cannot seem to change the camera's position in VR.
Of course I can change the camera's Tranform Position component numbers (i.e. x and y and z) but when I run in play mode, it becomes obvious that Oculus' seeing camera has not moved.
How do I move/change the Oculus' perspective, to adjust how the Unity world is seen through the 2 lenses?
Add a parent GameObject to the camera and move that one, don't modify the VR camera.
Expanding on Krzysztof's answer, I usually use something like this (I attach this component to the VR Camera, give it an empty game object as a parent, then set that game object to be the vrCameraHolder):
[RequireComponent(typeof(Camera))]
public class VRPlayer : MonoBehaviour
{
// set to be the parent of this object
public Transform vrCameraHolder;
// simple utility functions
public static Quaternion LocalToWorldRotation(Transform t, Quaternion localRot)
{
return t.rotation * localRot;
}
public static Quaternion WorldToLocalRotation(Transform t, Quaternion rot)
{
return Quaternion.Inverse(t.rotation) * rot;
}
// Gets the body part position in world space
public Vector3 GetBodyPartPosition(UnityEngine.XR.XRNode bodyPart)
{
return vrCameraHolder.localToWorldMatrix.MultiplyPoint(UnityEngine.XR.InputTracking.GetLocalPosition(bodyPart));
}
// Gets the body part rotation in world space
public Quaternion GetBodyPartRotation(UnityEngine.XR.XRNode bodyPart)
{
return LocalToWorldRotation(vrCameraHolder, UnityEngine.XR.InputTracking.GetLocalRotation(bodyPart));
}
// moves entire player body so that this becomes true
public void SetBodyPartPosition(UnityEngine.XR.XRNode bodyPart, Vector3 pos)
{
Vector3 bodyPartPos = vrCameraHolder.localToWorldMatrix.MultiplyPoint(UnityEngine.XR.InputTracking.GetLocalPosition(bodyPart));
vrCameraHolder.position += pos - bodyPartPos;
}
// if you want to change rotation you should probably only use this to keep the headset tilted the same way (y axis is up, so 0 is forward along x axis, 180 is backwards along x axis, 90 and 270 are along z axis, etc.)
public void SetBodyPartYRotation(UnityEngine.XR.XRNode bodyPart, float yRot)
{
Vector3 curRot = GetBodyPartRotation(bodyPart).eulerAngles;
SetBodyPartRotation(bodyPart, new Vector3(curRot.x, yRot, curRot.z));
}
// rotates entire player body so that this becomes true (but doesn't change position)
public void SetBodyPartRotation(UnityEngine.XR.XRNode bodyPart, Quaternion rot)
{
Quaternion curWorldRot = GetBodyPartRotation(bodyPart);
Quaternion cancelOutWorldRot = Quaternion.Inverse(curWorldRot);
float angle1;
Vector3 axis1;
cancelOutWorldRot.ToAngleAxis(out angle1, out axis1);
Vector3 bodyPartPosition = GetBodyPartPosition(bodyPart);
vrCameraHolder.RotateAround(bodyPartPosition, axis1, angle1);
// now player rotation = not rotated
float angle2;
Vector3 axis2;
rot.ToAngleAxis(out angle2, out axis2);
vrCameraHolder.RotateAround(bodyPartPosition, axis2, angle2);
}
// rotates entire player body so that this becomes true (but doesn't change position)
public void SetBodyPartRotation(UnityEngine.XR.XRNode bodyPart, Vector3 eulerAngles)
{
SetBodyPartRotation(bodyPart, Quaternion.Euler(eulerAngles));
}
}
I have this code here ,i am trying to move an object from one position to another ,on mouse click ,but everytime i run it it justs instantiate the projectile object in a specific position while it had to instantiate it in a the ffor object position
using UnityEngine;
using System.Collections;
public class Shoot : MonoBehaviour
{
public GameObject projectile;
public GameObject foot;
public GameObject mouse;
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector2 Target = Input.mousePosition;
Vector2 pos1 = Camera.main.ScreenToWorldPoint(Target);
GameObject newObj = (GameObject)GameObject.Instantiate(projectile);
Vector2 pos2 = foot.transform.position;
transform.position=Vector2.Lerp(pos2,pos1,Time.deltaTime);
}
}
There are several issues here, I'll address them one at a time. First, the code for moving the projectile is wired up wrong:
transform.position=Vector2.Lerp(pos2,pos1,Time.deltaTime);
You are moving the object that "Shoot" is attached to, not the new game object (newObj, as you have named it.)
Second, it's important to understand the Update pattern and how to properly use it. Update is run every frame. Time.deltaTime is how much time has passed between the last frame render and this one. This number is usually very small. Lastly, Input.GetMouseButtonDown is true only on the first frame that the mouse is pressed.
The current code you have only attempts to (but fails, due to other code problems) move the projectile the one frame the mouse is clicked. What we want is the mouse click to spawn a projectile, and the projectile to move forward EVERY update.
This will be best accomplished with two classes. I will call them Gun and SeekerBullet. The Gun class will be responsible for creating a bullet every time the mouse button is pressed. The SeekerBullet class will be responsible for moving the bullet to it's target.
Gun
public SeekerBullet ProjectilePrefab;
void Update()
{
if (Input.GetMouseButton(0))
{
Vector2 target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
FireBullet(target);
}
}
void FireBullet(Vector2 target)
{
GameObject projectile = (GameObject)GameObject.Instantiate(ProjectilePrefab, transform.position, Quaternion.Identity);
projectile.GetComponent<SeekerBullet>().Target = target;
}
SeekerBullet
public float MoveSpeed = 5;
public Vector2 Target { get; set; }
public void Update()
{
transform.position = Vector3.MoveTowards(transform.position, Target, MoveSpeed * Time.deltaTime);
if (transform.position == Target)
OnReachTarget();
}
void OnReachTarget()
{
// Do whatever you want here
Destroy(gameObject); // delete this seekerbullet
}
The main Idea I'm trying to stress is isolating your code to perform it's one function well. The gun shouldn't be responsible for moving the projectile, just creating it and telling it where to go.
Also, note that the projectile is starting wherever the Gun is. See this line
GameObject projectile = (GameObject)GameObject.Instantiate(ProjectilePrefab, transform.position, Quaternion.Identity);
The transform.position is the position of the gun object. If you want it to start at the foot, like you have in your code, you can re-implement that just like you have in your example.
Why don't you use Raycast. It's pretty simple. Here's an example (Moves the object (transform) in the direction and distance of translation.):
var obj:Transform;
var hit:RaycastHit;
var move: boolean = false;
var moveSpeed:float;
var moveTime:float;
private var startTime:float;
function Update ()
{
if (Input.GetButtonDown ("Fire1"))
{
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, hit, 10000)){
move = true;
startTime = Time.time;
}
}
if(move){
var curTime = Time.time;
var elapsedTime = curTime - startTime;
var amountToMove = elapsedTime / moveTime;
print(amountToMove);
obj.transform.position = Vector3.Lerp(obj.transform.position, hit.point, amountToMove);
if(obj.transform.position == hit.point){
move = false;
}
This code creates a plane, and a cube. Assign the above code to the plane, assign the cube to the obj var in the inspector. Click on the plane, and watch the fun.
This is pretty simple. You can use the Vector3.Lerp function to achieve this. Use raycasting to get the mouse click position or the touch position. Then use the initial and the final position in the lerp function. The initial position being the position that the gameobject is at now and the final position being the click / touch position.
You can find the article by The Game Contriver on the same here
Move to Touch / Click Position - The Game Contriver