So here's the problem in video form
https://pbs.twimg.com/tweet_video/CPsvjgbWoAACKCp.mp4
When not moving the ship the shield moves around just fine, but when you start moving it can only drag behind you and move a little bit, which is just no good at all. I can't figure out what I've done wrong here!
public class ShieldMovement : MonoBehaviour {
public Transform target; //player shield is attaced to
public float circSpeed = 0.1f; // Speed Shield moves around ship
private Vector3 direction = Vector3.up;
private float distance = 0.8f; // distance from player so it doesn't clip
private float deadzone = 0.15f;
private float separation;
private bool canMove = true;
private Vector3 shipPos;
private Rigidbody2D tRB;
private Rigidbody2D rb;
// Use this for initialization
void Start ()
{
tRB = target.GetComponent<Rigidbody2D>();
rb = GetComponent<Rigidbody2D>();
}
void OnCollisionEnter2D (Collision2D other)
{
canMove = false;
}
void OnCollisionStay2d(Collision2D other)
{
canMove = false;
}
void OnCollisionExit2D (Collision2D other)
{
canMove = true;
}
// Update is called once per frame
void Update () {
float rh = Input.GetAxisRaw("rightH");
float rv = Input.GetAxisRaw("rightV");
shipPos = target.position;
separation = Mathf.Abs((transform.position - shipPos).magnitude);
if(Mathf.Abs(rh) > deadzone || Mathf.Abs(rv) > deadzone)
{
Vector3 targetDir = new Vector3(rh, rv, 0.0f);
direction = Vector3.Slerp(transform.position-shipPos, targetDir, circSpeed);
}
Ray ray = new Ray(shipPos, direction); // cast ray in direction of point on circle shield is to go
if(canMove)
{
transform.position = ray.GetPoint(distance); //move shield to the ray as far as the distance
}
if(separation != distance) //If the shield get torn away from the ship
{
transform.position = ray.GetPoint(distance); //move shield to the ray as far as the distance
}
float angleY = transform.position.y - shipPos.y;
float angleX = -(transform.position.x - shipPos.x);
float angle = Mathf.Atan2 (angleY, angleX) * Mathf.Rad2Deg-90; //Get angle
if(Mathf.Abs(rh) > deadzone || Mathf.Abs(rv) > deadzone)
{
transform.rotation = Quaternion.AngleAxis(angle,Vector3.forward*-1); // keep shield facing outwards in respect to player
}
}
void FixedUpdate ()
{
if(!canMove)
{
tRB.velocity = new Vector2(0.0f, 0.0f);
rb.velocity = new Vector2(0.0f, 0.0f);
}
}
Thanks a million for any help :)
You need to move the shield along with the ship. You can do this by adding the ship velocity to the shield.
Something like:
shipPos = target.position;
transform.position += shipVelocity;
separation = Mathf.Abs((transform.position - shipPos).magnitude);
Or make the shield a child object of the ship.
OK, so all I needed to do was to make the shield a child AND get rid of the conditional statement around the transform.rotation so it wouldn't inherit the parent rotation and ruin the shield. It's the little things!
Related
So i'm having issues with a script I have, what it does is basically rotate the player graphics depending on where the mouse is aiming at. This works fine and as intended but my issue is that when I want to shoot on the opposite direction, that being the Left direction, it shoots the player instead of where it's aiming at.
I've decided to record a small video to show the problem.
https://streamable.com/02zqz
Here's the code to both the rotation and weapon script.
Rotating
public class Rotating : MonoBehaviour
{
public PlayerController player;
public float x;
public Vector3 flipArm;
void Start()
{
x = transform.localScale.x;
flipArm = transform.localScale;
player = GetComponentInParent<PlayerController>();
}
void Update()
{
Vector3 difference = Camera.main.ScreenToWorldPoint(Input.mousePosition ) - transform.position;
difference.Normalize();
float rotZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotZ + 0);
if(difference.x >= 0)
{
transform.rotation = Quaternion.Euler(0f, 0f, rotZ);
player.armRight = true;
}
else
{
transform.rotation = Quaternion.Euler(0f, 0f, rotZ+180);
player.armRight = false;
}
}
}
Weapon
public class Weapon : MonoBehaviour
{
public float shootDelay = 0;
public float damage = 1;
public LayerMask whatToHit;
public Transform firePoint;
public GameObject bullet;
// Start is called before the first frame update
void Start()
{
firePoint = transform.Find("FirePoint");
}
// Update is called once per frame
void Update()
{
shootDelay += Time.deltaTime;
if(shootDelay >= 0.1f)
{
if(Input.GetMouseButton(0))
{
shootDelay = 0;
Shot();
}
}
}
public void Shot()
{
Vector2 mousepos = new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
Vector2 firepointpos = new Vector2(firePoint.position.x, firePoint.position.y);
Instantiate(bullet, firepointpos, transform.rotation);
Debug.DrawLine(firepointpos, (mousepos - firepointpos) * 100, Color.cyan);
}
}
Try this:
transform.rotation = Quaternion.LookRotation ( end - start );
Also don't forget to check where the player is facing because you don't want to shoot from back. Using the above euler angles, one side is 90 and another 270 degrees in y component.
I have a ball that have a continuous bouncing, and I want to move it left and right in the x Axis with the mouse, so it follow the mouse's X movement.
I made the script bellow, but the ball didn't move with mouse!
Ball Script:
private Vector3 pos;
public Camera cam;
public Rigidbody Ball;
public float Speed;
public static float GlobalGravity = -9.8f;
public float GravityScale = 1.0f;
bool isforce = false;
private void Start(){
Ball = GetComponent<Rigidbody>();
Ball.useGravity = false;
}
private void FixedUpdate(){
Vector3 gravity = GlobalGravity * GravityScale * Vector3.up;
Ball.AddForce(gravity, ForceMode.Acceleration);
}
void force (){
isforce = false;
Ball.AddForce(Vector3.up * Speed, ForceMode.Impulse);
}
private void Update(){
if (isforce == true){
force();
}
if (Input.GetMouseButton(1)){
Vector3 mousePos = Input.mousePosition;
Vector3 wantedPos = Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x, transform.position.y, 10));
transform.position = wantedPos;
}
}
private void OnCollisionEnter(Collision collision){
isforce = true;
}
try this and let me know what happens. yours was set to right click, but i changed this one to left click, other than that i just sat the balls x to the raw x of the mouse input.
private void Update(){
if (isforce == true){
force();
}
if (Input.GetMouseButton(0)){
Vector3 mousePos = Input.mousePosition;
Vector3 wantedPos = transform.position;
wantedPos.x=Input.mousePosition.x;
transform.position = wantedPos;
}
}
When you use transform.position, the Unity Physics will no apply to the rigidBody. Find your mouse position relative to the ball and add Force in the X direction accordingly.
You have a couple of options depending on what it is you want.
Also as #Hamed answered, when using physics you don't want to update the transform directly but add force using the Rigidbody.
Force Constant relative to where the Mouse is
if (Input.GetMouseButton(0))
{
Vector2 force = Vector2.zero;
//Get the Balls current screenX position
float ballX = Camera.WorldToScreenPoint(Ball.transform.position).x;
//Check if Click was Left or Right of the Ball
if (ballX > Input.mousePosition.x)
{
//Click was Left of the Ball
force = new Vector2(-1f, 0f);
}
else if (ballX < Input.mousePosition.x)
{
//Click was Right of the Ball
force = new Vector2(1f, 0f);
}
//Adjust force amount to your suiting
Ball.Addforce(force * Time.deltaTime);
}
Force relative to the mouse movement
if (Input.GetMouseButton(0))
{
Vector2 force = Vector2.zero;
float mouseDelta = Input.GetAxis("Mouse X");
//Check if the Mouse is going Left or Right
if (mouseDelta < 0f)
{
//Click was Left of the Ball
force = new Vector2(-1f, 0f);
}
else if (mouseDelta > 0f)
{
//Click was Right of the Ball
force = new Vector2(1f, 0f);
}
// Update force relative to mouse movement
force = Mathf.Abs(mouseDelta) * force;
//Adjust force amount to your suiting
Ball.Addforce(force * Time.deltaTime)
}
Hastily written, look then write your own :)
I'm working on a third-person run-around game and there's a specific kind of movement I've wanted to achieve but I'm having trouble even imagining how it would work, let alone actually coding it.
Essentially, when holding left or right, I want the player to orbit the camera. Such a camera effect can be seen here. That's exactly what I want to achieve.
Here's my movement and camera code so far. I image I'll need to use the camera's Y rotation to achieve this but my tests haven't worked out. Any input would be appreciated!
Movement:
public int speed = 10;
public int rotationSpeed = 10;
public CharacterController cc;
Vector2 input;
Vector3 moveDir;
Vector3 lookDir;
Vector3 forward;
Transform camTransform;
public Transform model;
void Start () {
cc = GetComponent<CharacterController>();
camTransform = Camera.main.transform;
}
void GetInput() {
input.x = Input.GetAxisRaw("Horizontal");
input.y = Input.GetAxisRaw("Vertical");
}
void CalculateForward()
{
}
void Move()
{
moveDir.x = input.x;
moveDir.z = input.y;
if(moveDir.magnitude > 1)
{
moveDir.Normalize();
}
Vector3 rotatedDir = Camera.main.transform.TransformDirection(moveDir);
rotatedDir = new Vector3(rotatedDir.x, 0, rotatedDir.z);
rotatedDir = rotatedDir.normalized * moveDir.magnitude;
cc.Move(rotatedDir * speed * Time.deltaTime);
}
void ApplyGravity()
{
}
void FaceDir()
{
if (moveDir != Vector3.zero)
{
transform.rotation = Quaternion.Slerp(
transform.rotation,
Quaternion.LookRotation(-moveDir),
Time.deltaTime * rotationSpeed
);
}
}
private void FixedUpdate()
{
GetInput();
//ApplyGravity();
Move();
FaceDir();
ApplyGravity();
}
}
Camera:
[SerializeField]
private float distanceAway;
[SerializeField]
private float distanceUp;
[SerializeField]
private float smooth;
[SerializeField]
private Transform follow;
private Vector3 targetPosition;
private void Start()
{
follow = GameObject.FindWithTag("Player").transform;
}
private void LateUpdate()
{
targetPosition = follow.position + follow.up * distanceUp - follow.forward * distanceAway;
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * smooth);
transform.LookAt(follow);
}
Movement around a circle is always in a direction tangential to the circle, so with each update you want to:
Set the Y rotation of the player to be looking directly at the Y axis of the camera
rotate the player 90 degrees left or right (depending on the direction you want to go)
move the player forward a distance that will depend on the speed with which you would like them to move
Remember it's impossible to traverse a circle perfectly because there are infinitely many points on a circle but this approach will approximate it well enough.
When I use transform.Translate on my cube's x and z axis it moves according to pressing keys. But I want the cube to move back slowly to it's original position when user stops pressing keys and default axis are x=0 ,z=0.
public float move = 1f;
void Update ()
{
this.transform.Translate (Input.GetAxis ("Horizontal") / move, 0f, Input.GetAxis ("Vertical") / move);
}
So your best bet is to store the original position
private Vector3 _intialPosition;
private float _duration = 0.4f;
private float _startTime;
void Awake()
{
_initialPosition = transform.position;
}
void Start() {
_startTime = Time.time;
}
And then check if the key has been pressed, and if not, have it move back towards the initial position
void Update()
{
if(Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0)
{
//Logic here to move via arrows...
}
else
{
transform.position = Vector3.Lerp(transform.position, _initialPosition, (Time.time - _startTime ) / _duration);
}
}
Unity Documentation
Lerp
You could use Vector3.MoveTowards to slowly move your current transform to a target or original transform position.
private Transform original;
public float speed = 0.5f;
void Awake()
{
original = transform;
}
void Update() {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, original.position, step);
}
Unity3d documention - Vector3.MoveTowards
I am messing around in Unity and wanted to make a mechanic where a box would touch another object and then that object would follow the Player.
I have Cube set up like this:
And a Sphere with a Box Collider with same options.
My Player script is thus:
public class Player : MonoBehaviour {
public float speed = 0.0f;
public float moveX = 0.0f;
public float moveY = 0.0f;
public GameObject player;
public GameObject obj;
//public float force = 0.0f;
private bool collided = false;
// Use this for initialization
void Start () {
player = GameObject.FindWithTag ("Player");
}
// Update is called once per frame
void FixedUpdate () {
moveX = Input.GetAxis ("Horizontal");
moveY = Input.GetAxis ("Vertical");
player.GetComponent<Rigidbody> ().velocity = new Vector2 (moveX * speed, moveY * speed);
}
void OnCollisionEnter (Collision col) {
if (col.gameObject == obj) {
collided = true;
}
}
void OnCollisionExit (Collision col) {
if (col.gameObject == obj) {
collided = false;
}
}
void Update () {
if(collided) {
obj.transform.position = (player.transform.position - obj.transform.position)*speed;
}
}
}
What have I yet to do? Hoping someone can nudge me in the right direction.
I will provide you two scripts.
1st Script is FollowTarget. This will follow your target forcely.
2nd Script is SmoothFollow which will follow your target in a smooth movement.
FollowTarget.cs
using System;
using UnityEngine;
public class FollowTarget : MonoBehaviour
{
public Transform target;
public Vector3 offset = new Vector3(0f, 7.5f, 0f);
private void LateUpdate()
{
transform.position = target.position + offset;
}
}
SmoothFollow.cs
using UnityEngine;
public class SmoothFollow : MonoBehaviour
{
// The target we are following
[SerializeField]
private Transform target;
// The distance in the x-z plane to the target
[SerializeField]
private float distance = 10.0f;
// the height we want the camera to be above the target
[SerializeField]
private float height = 5.0f;
[SerializeField]
private float rotationDamping;
[SerializeField]
private float heightDamping;
// Use this for initialization
void Start() { }
// Update is called once per frame
void LateUpdate()
{
// Early out if we don't have a target
if (!target)
return;
// Calculate the current rotation angles
var wantedRotationAngle = target.eulerAngles.y;
var wantedHeight = target.position.y + height;
var currentRotationAngle = transform.eulerAngles.y;
var currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;
// Set the height of the camera
transform.position = new Vector3(transform.position.x ,currentHeight , transform.position.z);
// Always look at the target
transform.LookAt(target);
}
}
Just choose one of them and then attach it to the gameObject. Like another box that is suppose to follow.
Remove your Update() function in your script as you don't need it anymore.
Also Remove your OnCollisionExit()
void OnCollisionEnter (Collision col) {
if (col.gameObject == obj) {
// If you choose to use SmoothFollow Uncomment this.
//col.GetComponent<SmoothFollow>().target = this.transform;
// If you choose to use FollowTarget Uncomment this
//col.GetComponent<FollowTarget>().target = this.transform;
}
}