Unity C# transform.LookAt rotating on wrong axis - unity3d

Im making the basic foundations of an RPG game. Its point and click, using a navmesh. I have set up the player to move to an enemy and attack when in range. The problem i am having is that when the player reaches the enemy (or the chest/interactable) it rotates on the x axis. Im assuming its something to do with the lookAt function using the pivot point of the target object, but i cannot find a solution. Any help directing me to a solution would be amazing. I have scoured sites, forums and the Unity API for a couple of days now. Im sure its something simple, i just cant seem to see it.
Much love
public class clickToMove : MonoBehaviour
{
// Attack variables
[Header("Attack")]
public float attackDistance;
public float attackRate;
private float nextAttack;
//Navigation variables
private NavMeshAgent navMeshAgent;
//private bool walking;
//Animation variables
private Animator anim;
//Enemy variables
private Transform targetedEnemy;
private bool enemyClicked;
//Interactable variables
private Transform targetedObject;
private bool objectClicked;
void Awake()
{
anim = GetComponent<Animator>();
navMeshAgent = GetComponent<NavMeshAgent>();
}
void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Input.GetButton("Fire1"))
{
navMeshAgent.ResetPath();
if(Physics.Raycast(ray, out hit, 1000))
{
if(hit.collider.tag == "Enemy")
{
enemyClicked = true;
targetedEnemy = hit.transform;
}
else if (hit.collider.tag == "Chest")
{
objectClicked = true;
targetedObject = hit.transform;
}
else if(hit.collider.tag == "Player")
{
//walking = false;
navMeshAgent.isStopped = true;
}
else
{
//walking = true;
enemyClicked = false;
navMeshAgent.isStopped = false;
navMeshAgent.destination = hit.point;
}
}
}
if (enemyClicked)
{
MoveAndAttack();
}
else if(objectClicked && targetedObject.gameObject.tag == "Chest")
{
Interaction(targetedObject);
}
else
{
if (!navMeshAgent.pathPending && navMeshAgent.remainingDistance <= navMeshAgent.stoppingDistance)
{
//walking = false;
}
else if (!navMeshAgent.pathPending && navMeshAgent.remainingDistance >= navMeshAgent.stoppingDistance)
{
//walking = true;
}
}
//anim.SetBool("isWalking", walking);
//TODO: needs finishing. Still need to lock it to the y axis to stop its rotation being funny.
if (Input.GetKey(KeyCode.LeftShift))
{
//walking = false;
navMeshAgent.isStopped = true;
transform.LookAt(ray.origin + ray.direction * ((transform.position - Camera.main.transform.position).magnitude * 0.5f));
}
}
// TODO: still a bug where the player rotates 15 deg on x axis when it reaches target. Has something to do with the Lookat function.
void MoveAndAttack()
{
if (targetedEnemy == null)
{
return;
}
navMeshAgent.destination = targetedEnemy.position;
if (!navMeshAgent.pathPending && navMeshAgent.remainingDistance >= attackDistance)
{
navMeshAgent.isStopped = false;
//walking = true;
}
else if (!navMeshAgent.pathPending && navMeshAgent.remainingDistance <= attackDistance)
{
//anim.SetBool("isAttacking", false);
transform.LookAt(targetedEnemy);
Vector3 dirToAttack = targetedEnemy.transform.position - transform.position;
if(Time.time > nextAttack)
{
nextAttack = Time.time + attackRate;
//anim.SetBool("isAttacking", true);
}
navMeshAgent.isStopped = true;
//walking = false;
}
}
void Interaction(Transform target)
{
// set target
navMeshAgent.destination = target.position;
//go close to the target
if(!navMeshAgent.pathPending && navMeshAgent.remainingDistance > attackDistance)
{
navMeshAgent.isStopped = false;
//walking = true;
}
//read the info
else if (!navMeshAgent.pathPending && navMeshAgent.remainingDistance <= attackDistance)
{
navMeshAgent.isStopped = true;
transform.LookAt(targetedObject);
//walking = false;
//play animation
//target.gameObject.getComponentInChildren<Animator>().SetTrigger("Open");
objectClicked = false;
navMeshAgent.ResetPath();
}
}
}

Related

Creating top down 2D whip mechanic

What Whip should look like
I'm trying to create a whip that can extend in any direction the mouse is facing after pressing a certain button. If there are "grabbable" objects in the way such as an enemy or box, it should latch onto those objects and pull them around to collide with other objects for a certain amount of time.
I know that I need the different sprite shots of the whip extending and latching for animation, but I have no idea how to implement this in code and how to get the whip to stop short if it detects a "grabbable" object.
Attach this script to your player, this should get the job done:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Transform player = null;
public float speed = 30f;
public string grabbableTag = "grabbable";
private LineRenderer line = null;
private float timer = 0f;
private bool grabbing = false;
private bool reached = false;
private Vector2 from = Vector2.zero;
private Vector2 to = Vector2.zero;
private Vector2 target = Vector2.zero;
private Transform grabbable = null;
private void Start()
{
player = transform;
line = new GameObject("Line").AddComponent<LineRenderer>();
line.startColor = Color.red;
line.endColor = Color.red;
// Assign a material
line.gameObject.SetActive(false);
reached = false;
grabbing = false;
}
private void Update()
{
if(grabbing)
{
Grabbing();
}
else
{
if (Input.GetMouseButtonDown(0))
{
Grab();
}
}
}
private void Grab()
{
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = Vector3.Distance(player.position, Camera.main.transform.position);
to = Camera.main.ScreenToWorldPoint(mousePosition);
from = player.position;
Vector2 direction = (to - from).normalized;
float distance = Vector2.Distance(from, to);
RaycastHit2D[] hits = Physics2D.RaycastAll(from, direction, distance);
grabbable = null;
for (int i = 0; i < hits.Length; i++)
{
if (hits[i].transform.tag == grabbableTag)
{
grabbable = hits[i].transform;
break;
}
}
if (grabbable != null)
{
distance = Vector2.Distance(player.position, grabbable.position);
to = from + direction * distance;
}
grabbing = true;
reached = false;
target = from;
timer = 0;
line.gameObject.SetActive(true);
line.positionCount = 2;
line.SetPosition(0, from);
line.SetPosition(1, from);
}
private void Grabbing()
{
if (reached)
{
target = Vector2.Lerp(target, from, speed * Time.deltaTime);
if (target == from)
{
GrabDone(grabbable);
grabbing = false;
line.gameObject.SetActive(false);
}
}
else
{
target = Vector2.Lerp(target, to, speed * Time.deltaTime);
if(target == to)
{
reached = true;
}
}
line.SetPosition(1, target);
if (reached && grabbable != null)
{
grabbable.position = target;
}
}
private void GrabDone(Transform grabbed)
{
if(grabbed != null)
{
// Do somthing ...
Destroy(grabbed.gameObject);
}
}
}

Compiler generates "error CS1513: } expected", but } is there

I am following a tutorial where I build my first 2D game in Unity.
I added a flipX function to flip my Sprite when I change my direction (pressing A or D)
I tried to use the same script, and tried to compile it there are 2 errors:
Assets\Scripts\Player.cs(83,25): error CS1002: ; expected
Assets\Scripts\Player.cs(83,25): error CS1513: } expected
I know what they mean and checked my script. I'm sure they are there where they are not. I just can't figure out the error.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
private Rigidbody2D _rigid;
[SerializeField]
private float _jumpForce = 5.0f;
private bool _resetJump = false;
[SerializeField]
private float _speed = 3.5f;
private PlayerAnimation _playerAnim;
private SpriteRenderer _playerSprite;
// Start is called before the first frame update
void Start()
{
_rigid = GetComponent<Rigidbody2D>();
_playerAnim = GetComponent<PlayerAnimation>();
_playerSprite = GetComponentInChildren<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
Movement();
}
void Movement()
{
float horizontalInput = Input.GetAxisRaw("Horizontal");
if (horizontalInput > 0)
{
Flip(true);
}
else if (horizontalInput < 0)
{
Flip(false);
}
if (Input.GetKeyDown(KeyCode.Space) && IsGrounded() == true)
{
Debug.Log("Jump!");
_rigid.velocity = new Vector2(_rigid.velocity.x, _jumpForce);
StartCoroutine(ResetJumpRoutine());
}
_rigid.velocity = new Vector2(horizontalInput * _speed, _rigid.velocity.y);
_playerAnim.Move(horizontalInput);
}
bool IsGrounded()
{
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector2.down, 0.6f, 1 << 8);
if (hitInfo.collider != null)
{
if (_resetJump == false)
return true;
}
return false;
}
void Flip(bool faceRight)
{
if (faceRight == true)
{
_playerSprite.flipX = false;
}
else if (faceRight == false)
{
_playerSprite,flipX = true;
}
}
IEnumerator ResetJumpRoutine()
{
_resetJump = true;
yield return new WaitForSeconds(0.1f);
_resetJump = false;
}
}
It's a simple mistake, replace _playerSprite,flipX = true; with _playerSprite.flipX = true;.
You have a comma instead of a dot.

Spring Joint 2D (maybe) causing transform.position errors

I know the title might be misleading after you see what is the problem, but I really don't know how to name this issue.
The first picture shows the problem.
The white line shows the distance between the player and the gameobject called hook. The blue sprite sphere close to the hook is the SpringJoint2D.connectedBody.
They both (the white line and the blue sprite) are working with the same value: hook.transform.position.
Here is the code snippets which I believe are causing problems or at least reveal the most:
SpringJoint2D snippet:
if (Input.GetMouseButtonDown(0))
{
hook = FindClosestObject(radius, "Hook");
if(hook != null)
{
joint.enabled = true;
joint.connectedBody = hook;
joint.connectedAnchor = hook.transform.position;
Debug.Log("Click.");
Debug.Log(hook);
}
}
if (Input.GetMouseButtonUp(0))
{
joint.enabled = false;
joint.connectedBody = null;
}
Debug.DrawLine snippet:
if (hook != null)
{
joint.distance = Vector3.Distance(hook.transform.position, transform.position) / 2;
Debug.DrawLine(transform.position, hook.transform.position);
}
And here is the whole code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerScript : MonoBehaviour
{
public float radius;
private SpringJoint2D joint;
private Rigidbody2D hook = new Rigidbody2D();
// Start is called before the first frame update
void Start()
{
joint = GetComponent<SpringJoint2D>();
}
// Update is called once per frame
void Update()
{
//touch.phase == TouchPhase.Began
if (Input.GetMouseButtonDown(0))
{
hook = FindClosestObject(radius, "Hook");
if(hook != null)
{
joint.enabled = true;
joint.connectedBody = hook;
joint.connectedAnchor = hook.transform.position;
Debug.Log("Click.");
Debug.Log(hook);
}
}
if (Input.GetMouseButtonUp(0))
{
joint.enabled = false;
joint.connectedBody = null;
}
//foreach (Touch touch in Input.touches)
//{
//}
if (hook != null)
{
joint.distance = Vector3.Distance(hook.transform.position, transform.position) / 2;
Debug.DrawLine(transform.position, hook.transform.position);
}
}
private void OnDrawGizmos()
{
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(transform.position, radius);
if (hook != null)
Gizmos.DrawLine(transform.position, hook.transform.position);
}
public Rigidbody2D FindClosestObject(float radius, string tag)
{
GameObject[] gos;
gos = GameObject.FindGameObjectsWithTag(tag);
Rigidbody2D closest = null;
float distance = radius;
Vector3 position = transform.position;
foreach (GameObject go in gos)
{
Vector3 diff = go.transform.position - position;
float curDistance = diff.sqrMagnitude;
if (curDistance < distance)
{
closest = go.GetComponent<Rigidbody2D>();
distance = curDistance;
}
}
return closest;
}
}
Ah, I was just stupid.
There is no need to assign the connectedAnchor if you also asign the connectedRigidbody2D
The connectedAnchor is the offset from the connectedRigidbody2D's position...

Player want to move left and right from single - touch (Unity)

I made the game in Unity Space Shooter. In my Space shooter there is 2 button it work for Left and Right moving. I want when we touch the left button player go to left only in Single Touch same like Right Button also.
This , are the some codes which i used in Game. Please Help me out from this.
TouchControl.cs
using UnityEngine;
using System.Collections;
public class TouchControl : MonoBehaviour {
public GUITexture moveLeft;
public GUITexture moveRight;
public GUITexture fire;
public GameObject player;
private PlayerMovement playerMove;
private Weapon[] weapons;
void Start()
{
playerMove = player.GetComponent<PlayerMovement> ();
}
void CallFire()
{
weapons = player.GetComponentsInChildren<Weapon> ();
foreach (Weapon weapon in weapons) {
if(weapon.enabled == true)
weapon.Fire();
}
}
void Update()
{
// int i = 0;
if(Input.touchCount > 0)
{
for(int i =0; i < Input.touchCount; i++)
{
// if(moveLeft.HitTest(Input.GetTouch(i).position, Camera.main))
// {
// if(Input.touchCount > 0)
// {
// playerMove.MoveLeft();
// }
// }
// if(moveRight.HitTest(Input.GetTouch(i).position, Camera.main))
// {
// if(Input.touchCount > 0)
// {
// playerMove.MoveRight();
// }
// }
// if(moveLeft.HitTest(Input.GetTouch(i).position, Camera.main))
// {
// if(Input.touchCount > 0)
// {
// CallFire();
// }
// }
// Touch t = Input.GetTouch(i);
Touch t = Input.GetTouch (i);
Input.multiTouchEnabled = true;
if(t.phase == TouchPhase.Began || t.phase == TouchPhase.Stationary)
{
if(moveLeft.HitTest(t.position, Camera.main))
{
playerMove.MoveLeft ();
}
if(moveRight.HitTest(t.position, Camera.main))
{
playerMove.MoveRight();
}
}
if(t.phase == TouchPhase.Began)
{
if(fire.HitTest(t.position, Camera.main))
{
CallFire();
}
}
if(t.phase == TouchPhase.Ended)
{
}
}
}
}
}
PlayerMovement.cs
using UnityEngine;
using System.Collections;
public class PlayerMovement : MonoBehaviour {
public float speedMove = 6.0f;
public float bonusTime;
private bool toLeft = false;
private bool toRight = false;
public GameObject shield;
public GUIText bonustimeText;
private bool counting = false;
private float counter;
private Weapon[] addWeapons;
public Sprite strongShip;
public Sprite normalSprite;
public Sprite shieldSprite;
private SpriteRenderer sRender;
private Weapon weaponScript;
void Start () {
counter = bonusTime;
sRender = GetComponent<SpriteRenderer> ();
addWeapons = GetComponentsInChildren<Weapon> ();
foreach (Weapon addWeapon in addWeapons) {
addWeapon.enabled = false;
}
weaponScript = GetComponent<Weapon>();
weaponScript.enabled = true;
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.A)) {
toLeft = true;
}
if (Input.GetKeyUp (KeyCode.A)) {
toLeft = false;
}
if (Input.GetKeyDown (KeyCode.D)) {
toRight = true;
}
if (Input.GetKeyUp (KeyCode.D)) {
toRight = false;
}
if (counting) {
counter -= Time.deltaTime;
bonustimeText.text = counter.ToString("#0.0");
}
}
void FixedUpdate()
{
if (toLeft) {
MoveLeft();
}
if (toRight) {
MoveRight();
}
}
public void MoveLeft()
{
transform.Translate(Vector2.right * -speedMove* Time.deltaTime);
}
public void MoveRight()
{
transform.Translate(Vector2.right * speedMove * Time.deltaTime);
}
void OnCollisionEnter2D(Collision2D coll)
{
if (coll.gameObject.tag == "StrongMode") {
Destroy (coll.gameObject);
counting = true;
StrongMode();
Invoke ("Downgrade", bonusTime);
}
if (coll.gameObject.tag == "ShieldMode") {
Destroy (coll.gameObject);
counting = true;
ShieldMode();
Invoke("Downgrade", bonusTime);
}
if (coll.gameObject.tag == "Life") {
GUIHealth gui = GameObject.Find ("GUI").GetComponent<GUIHealth> ();
gui.AddHealth();
SendMessage("AddHp");
SoundHelper.instanceSound.PickUpSound();
Destroy(coll.gameObject);
}
if (coll.gameObject.tag == "Enemy") {
SendMessage("Dead");
}
}
void Downgrade()
{
SoundHelper.instanceSound.BonusDownSound ();
counting = false;
bonustimeText.text = "";
counter = bonusTime;
sRender.sprite = normalSprite;
weaponScript.enabled = true;
foreach (Weapon addWeapon in addWeapons) {
addWeapon.enabled = false;
}
weaponScript.enabled = true;
shield.SetActive (false);
}
void StrongMode()
{
SoundHelper.instanceSound.BonusUpSound ();
sRender.sprite = strongShip;
foreach (Weapon addWeapon in addWeapons) {
addWeapon.enabled = true;
}
weaponScript.enabled = false;
}
void ShieldMode()
{
SoundHelper.instanceSound.BonusUpSound ();
sRender.sprite = shieldSprite;
shield.SetActive (true);
}
// void OnDestroy()
// {
// bonustimeText.text = "";
// }
}
In the Player Controller script Create:
public Vector3 playerDirection = Vector3.zero;
Then in touch control instead of:
if (moveLeft.HitTest(Input.GetTouch(i).position, Camera.main))
{
if (Input.touchCount > 0)
{
playerMove.MoveLeft();
}
}
if (moveRight.HitTest(Input.GetTouch(i).position, Camera.main))
{
if (Input.touchCount > 0)
{
playerMove.MoveRight();
}
}
Use:
if (moveLeft.HitTest(Input.GetTouch(i).position, Camera.main))
{
if (Input.touchCount > 0)
{
playerMove.playerDirection = Vector3.left;
}
}
if (moveRight.HitTest(Input.GetTouch(i).position, Camera.main))
{
if (Input.touchCount > 0)
{
playerMove.playerDirection = Vector3.right;
}
}
Then in the Update method of Player Controller use:
transform.Translate(playerDirection * speedMove * Time.deltaTime);
public class PlayerController {
public EPlayerState playerState = EPLayerState.Idle;
void Update () {
// If click right button
playerState = EPlayerState.MoveRight;
// Else if click left button
playerState = EPlayerState.MoveLeft
if (playerState == EPlayerState.MoveRight)
// Move player right;
if (playerState == EPlayerState.MoveLeft
// Move player right;
}
}
public enum EPlayerState {
Idle,
MoveRight,
MoveLeft
}
You can also use something like a boolean called isRight, move right when it's true and left when it's false. Then when you click left or right button just change the variable.
`using UnityEngine;
public class HalfScreenTouchMovement : MonoBehaviour
{
private float screenCenterX;
private void Start()
{
// save the horizontal center of the screen
screenCenterX = Screen.width * 0.5f;
}
private void Update()
{
// if there are any touches currently
if(Input.touchCount > 0)
{
// get the first one
Touch firstTouch = Input.GetTouch(0);
// if it began this frame
if(firstTouch.phase == TouchPhase.Began)
{
if(firstTouch.position.x > screenCenterX)
{
// if the touch position is to the right of center
// move right
}
else if(firstTouch.position.x < screenCenterX)
{
// if the touch position is to the left of center
// move left
}
}
}
}
}`
May be helpfull
create script. for example player.cs
public class PlayerController : MonoBehaviour
{
bool swipeRight = false;
bool swipeLeft = false;
bool touchBlock = true;
bool canTouchRight = true;
bool canTouchLeft = true;
void Update()
{
swipeLeft = Input.GetKeyDown("a") || Input.GetKeyDown(KeyCode.LeftArrow);
swipeRight = Input.GetKeyDown("d") || Input.GetKeyDown(KeyCode.RightArrow);
TouchControl();
if(swipeRight) //rightMove logic
else if(swipeLeft) //leftMove logic
}
void TouchControl()
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved && touchBlock == true)
{
touchBlock = false;
// Get movement of the finger since last frame
var touchDeltaPosition = Input.GetTouch(0).deltaPosition;
Debug.Log("touchDeltaPosition "+touchDeltaPosition);
if(touchDeltaPosition.x > 0 && canTouchRight == true)
{
//rightMove
swipeRight = true; canTouchRight = false;
Invoke("DisableSwipeRight",0.2f);
}
else if(touchDeltaPosition.x < 0 && canTouchLeft == true)
{
//leftMove
swipeLeft = true; canTouchLeft = false;
Invoke("DisableSwipeLeft",0.2f);
}
}
}
void DisableSwipeLeft()
{
swipeLeft = false;
touchBlock = true;
canTouchLeft = true;
}
void DisableSwipeRight()
{
swipeRight = false;
touchBlock = true;
canTouchRight = true;
}
}

Tiling for a 2D platform in Unity

I was following a tutorial online, and basically the script is telling the gameObject to instantiate a clone of itself if the camera gets to a certain position. The last lines that I am confused about are these
if (rightOrLeft > 0)
{
newBuddy.GetComponent<Tiling>().hasALeftBuddy = true;
}
else
{
newBuddy.GetComponent<Tiling>().hasARightBuddy = true;
}
}
In short, I'm not really up to par with the syntax or math right here. Could someone please help in clearing it up for me?
using UnityEngine;
using System.Collections;
[RequireComponent (typeof(SpriteRenderer))]
public class Tiling : MonoBehaviour {
public int offsetX = 2;
public bool hasARightBuddy = false;
public bool hasALeftBuddy = false;
public bool reverseScale = false;
private float spriteWidth = 0f;
private Camera cam;
private Transform myTransform;
void Awake () {
cam = Camera.main;
myTransform = transform;
}
// Use this for initialization
void Start () {
SpriteRenderer sRenderer = GetComponent<SpriteRenderer>();
spriteWidth = sRenderer.sprite.bounds.size.x;
}
// Update is called once per frame
void Update ()
{
if (hasALeftBuddy == false || hasARightBuddy == false)
{
float camHorizontalExtend = cam.orthographicSize * Screen.width/Screen.height;
float edgeVisiblePositionRight = (myTransform.position.x + spriteWidth/2) - camHorizontalExtend; //sprite width/2..51.2
//(0 + 51.2 - 26.67315 = 24.52685)
//(102.4 + 51.2 - 26.67315 = 126.92685) etc.. //clone of the myTransform
float edgeVisiblePositionLeft = (myTransform.position.x - spriteWidth/2) + camHorizontalExtend; // (0 - 51.2 + 26.67315 = -24.52685)
// (-102.4 - 51.2 + 26.67315 = -126.92685) etc..//clone of the myTransform
if (cam.transform.position.x >= edgeVisiblePositionRight - offsetX && hasARightBuddy == false)
{
MakeNewBuddy (1);
hasARightBuddy = true;
}
else if (cam.transform.position.x <= edgeVisiblePositionLeft + offsetX && hasALeftBuddy == false)
{
MakeNewBuddy (-1);
hasALeftBuddy = true;
}
}
}
void MakeNewBuddy (int rightOrLeft)
{
Vector3 newPosition = new Vector3 (myTransform.position.x + spriteWidth * rightOrLeft, myTransform.position.y, myTransform.position.z);
Transform newBuddy = Instantiate (myTransform, newPosition, myTransform.rotation) as Transform;
if (reverseScale == true)
{
newBuddy.localScale = new Vector3 (newBuddy.localScale.x*-1, newBuddy.localScale.y, newBuddy.localScale.z);
}
if (rightOrLeft > 0)
{
newBuddy.GetComponent<Tiling>().hasALeftBuddy = true;
}
else
{
newBuddy.GetComponent<Tiling>().hasARightBuddy = true;
}
}
}
}
looks to me like the code is telling the current game object that it has a neighbour when the new neighbour is created.
The boolean has a neighbour variables are handy for figuring out that this creation process doesn't need to happen again :)