I have a little problem with this code:
private void Update()
{
if (Input.GetMouseButtonDown(0) && canClick)
{
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mouseWorldPosition.z = player.transform.position.z;
directionVector = player.transform.position - mouseWorldPosition;
player.GetComponent<Rigidbody2D>().AddForce(directionVector.normalized * speed);
Quaternion InstanceRotation = Quaternion.Euler(mouseWorldPosition.x - 90f, 0f, 0f);
GameObject effect = Instantiate(SteamFx, mouseWorldPosition, InstanceRotation);
effect.transform.LookAt(directionVector);
}
}
The problem is that when instantiating the object, it has a z rotation. So I have an effect that when I click on the screen, it should instantiate, and blow in the player direction. It has different rotation, how to make the rotation correct.
Thks!!!
Related
I am creating a 2d mobile game where one of the scripts uses a joystick to move and the other script lets the player shoot an object when tapping anywhere on the screen. The issue is when using the joystick it also shoots at the same time in that direction. Is there a way to separate the touches so when you use the joystick it does not immediately shoot to that direction but the player can still move and shoot anywhere at the same time?
Move Code
private void Update()
{
Vector2 moveInput = new Vector2(joystick.Horizontal, joystick.Vertical);
moveAmount = moveInput.normalized * speed;
}
Shoot code
private void Update()
{
Vector2 direction = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle - 90, Vector3.forward);
transform.rotation = rotation;
if(Input.GetMouseButton(0))
{
if (Time.time >= shotTime)
{
Instantiate(projectile, shotPoint.position, transform.rotation);
shotTime = Time.time + timeBetweenShots;
}
}
}
Instead of using Input.mousePosition you'll have to use Input.GetTouch. You can loop through it using Input.touchCount to find the first touch that is not interacting with a ui element, than use that touch instead of Input.mousePosition to find the direction to shoot (or not shoot if there is no touch). To find out if a specific touch is over ui you need a reference to the scene's EventSystem (or use EventSystem.current), and use EventSystem.IsPointerOverGameObject with Touch.fingerId.
If the joystick is not a ui element you'll need a different way to detect if the touch is over the joystick. For example you could check the pixel position, or see if the joystick itself has an "interacting fingerId". But with the assumption that the joystick is an ui element, here's one way to do what I wrote above: (untested)
private void Update()
{
var eventSystem = EventSystem.current;
for (var i = 0; i<Input.touchCount; i++)
{
var touch = Input.GetTouch(i);
if (eventSystem.IsPointerOverGameObject(touch.fingerId))
{
continue;
}
ShootToScreenPos(Vector2 screenPos);
break;
}
}
private void ShootToScreenPos(Vector2 screenPos)
{
Vector2 direction = Camera.main.ScreenToWorldPoint(screenPos) - transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle - 90, Vector3.forward);
transform.rotation = rotation;
if (Time.time >= shotTime)
{
Instantiate(projectile, shotPoint.position, transform.rotation);
shotTime = Time.time + timeBetweenShots;
}
}
I am using a Cinemachine state driver to transition between my 8 directional cameras orbiting my player. Right now my player script is set to a basic isometric character controller:
Player.cs
public float speed = 5f;
Vector3 forward;
Vector3 right;
// Start is called before the first frame update
void Start()
{
forward = Camera.main.transform.forward;
forward.y = 0;
forward = Vector3.Normalize(forward);
right = Quaternion.Euler(new Vector3(0, 90, 0)) * forward;
}
// Update is called once per frame
void Update()
{
if (Input.anyKey)
{
Move();
}
}
void Move ()
{
Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 rightMovement = right * speed * Time.deltaTime * Input.GetAxis("Horizontal");
Vector3 upMovement = forward * speed * Time.deltaTime * Input.GetAxis("Vertical");
Vector3 heading = Vector3.Normalize(rightMovement + upMovement);
transform.forward += heading;
transform.position += rightMovement;
transform.position += upMovement;
}
I want the players move direction to reflect the direction of the camera. For example, using W (from WASD) will always move the player up. Could I edit the script to pick up the direction of each of my virtual cameras and add that to my player controller or is there a better way?
To solve this problem you have to change the movement of the keys according to the angle of the camera. This is done as follows with transform.TransformDirection. When the movement is synchronized with the direction of the camera, it causes the W key to press the character towards the ground, because the angle in front of the camera is inside the ground. To solve the problem, we set y to zero and then normalize the axis.
public float speed = 10f;
void Update()
{
var moveInput = new Vector3(Input.GetAxis("Horizontal"), 0f , Input.GetAxis("Vertical"));
moveInput = Camera.main.transform.TransformDirection(moveInput);
moveInput.y = 0;
moveInput = moveInput.normalized;
transform.position += moveInput * Time.deltaTime * speed;
}
I want to move my player character(human) on a curved surface. But at the same time character shall stay perpendicular to the surface normals and it should face in the movement direction and can handle collisions(if there is a wall ahead, shall not be able to go through it).
I tried to make a parent stay over normals and change the child local rotation towards direction of motion of its parent. But it has several limitations as of now.
Here is the code what i was using:
[SerializeField] float raycastLength = 1f;
bool canPlayerMove = true;
public float speed = 2f;
public Vector3 offset; //object's position offset to ground / surface
public Quaternion childDirection;
private void Update()
{
float moveHorizontal = SimpleInput.GetAxis("Horizontal");
float moveVertical = SimpleInput.GetAxis("Vertical");
Ray ray = new Ray(transform.position, -transform.up);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo, raycastLength))
{
transform.rotation = Quaternion.LookRotation(Vector3.up, hitInfo.normal);
transform.position = hitInfo.point + offset;
Debug.DrawLine(ray.origin, hitInfo.point, Color.red);
}
if (canPlayerMove)
{
Vector3 movement = new Vector3(moveHorizontal, 0, moveVertical);
if (movement != Vector3.zero)
{
childDirection = Quaternion.Slerp(transform.GetChild(0).localRotation, Quaternion.LookRotation(movement), 0.15F);
transform.GetChild(0).localRotation = childDirection;
}
transform.Translate(movement * speed * Time.deltaTime, Space.Self);
}
}
first to not make your player go thru walls you want to add a collider to your walls and not set it as trigger, you will also need a rigidbody on your player and this will help in the next steps.
Secondly you will need to acces the rigidBody in code using this: (if you Check Use Gravity it will also stay on your terrain that you made)
private Rigidbody rb;
private float speed = 7.5f;
private void Start()
{
//this gets the rigidbody on the gameObject the script is currently on.
rb = this.GetComponent<Rigidbody>();
}
private void Update()
{
float hor = Input.GetAxis("Horizontal");
float vert = Input.GetAxis("Vertical");
//this will move your player frame independent.
rb.MovePosition(this.transform.position + new Vector3(hor, 0, vert) * speed *
Time.deltaTime);
}
Also make sure that you have a rigidBody on your player, else it will throw an error.
I have a problem with the Translate function. What I'm trying to do is to open doors by clicking on them. I succeeded in doing this with all the doors, but now I've added a new one and when I close it, it doesn't go back to its position.
I'll try to explain the problem better showing the code:
public override void OpeningDoor() {
Vector3 movement = new Vector3 (2.006f, 0.0f,1.793f);
Vector3 rotate = new Vector3 (0.0f, 108.3f, 0.0f);
transform.Translate (movement);
transform.Rotate (rotate);
toClose = true;
}
public override void ClosingDoor() {
Debug.Log ("Closing Door");
Vector3 movement = new Vector3 (-2.006f, 0.0f,-1.793f);
Vector3 rotate = new Vector3 (0.0f, -108.3f, 0.0f);
transform.Translate (movement);
transform.Rotate (rotate);
toClose = false;
}
The rotation is okay, no problem with that. Also when I open the door it goes to
the right position, but when I close it, it doesn't go back to its position and it translates to a wrong one. Theoretically I just apply a certain movement on the X axis and Z axis, and when I close the door I decrement them of the same value.
I hope I've clearly explained the problem, if not please tell me.
Try changing the order of the transform.Rotate and transform.Translate lines in your ClosingDoor function.
Because the translation is relative to the orientation of the door, translating it before it's rotated will move it to the wrong place.
public override void OpeningDoor() {
Vector3 movement = new Vector3 (2.006f, 0.0f,1.793f);
Vector3 rotate = new Vector3 (0.0f, 108.3f, 0.0f);
transform.Translate (movement);
transform.Rotate (rotate);
toClose = true;
}
public override void ClosingDoor() {
Debug.Log ("Closing Door");
Vector3 movement = new Vector3 (-2.006f, 0.0f,-1.793f);
Vector3 rotate = new Vector3 (0.0f, -108.3f, 0.0f);
transform.Rotate (rotate);
transform.Translate (movement);
toClose = false;
}
I've created a simple drag script. This will be the main input of my game and that's how I'll control the player. The script can be seen below:
public void OnMouseDown() {
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
if (gameController.GetCurrentState () != GameStates.INGAME){
gameController.StartGame();
}
}
public void OnMouseDrag() {
if (gameController.GetCurrentState () == GameStates.INGAME) {
Vector3 curScreenPoint = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint (curScreenPoint) + offset;
transform.position = curPosition;
}
}
This script is attached to my player. Also attached to my player is a RigidBody 2D and Circle Collider 2D. I've created some walls and at game start, I'm repositioning it outside of the camera using mainCam.ScreenToWorldPoint. This is done with:
var mainCam : Camera;
var topWall : BoxCollider2D;
var bottomWall : BoxCollider2D;
var leftWall : BoxCollider2D;
var rightWall : BoxCollider2D;
//Reference the players
function Start () {
//Move each wall to its edge location:
topWall.size = new Vector2 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 2f, 0f, 0f)).x, 1f);
topWall.center = new Vector2 (0f, mainCam.ScreenToWorldPoint (new Vector3 ( 0f, Screen.height, 0f)).y + 0.5f);
bottomWall.size = new Vector2 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 2, 0f, 0f)).x, 1f);
bottomWall.center = new Vector2 (0f, mainCam.ScreenToWorldPoint (new Vector3( 0f, 0f, 0f)).y - 0.5f);
leftWall.size = new Vector2(1f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.height*2f, 0f)).y);;
leftWall.center = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(0f, 0f, 0f)).x - 0.5f, 0f);
rightWall.size = new Vector2(1f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.height*2f, 0f)).y);
rightWall.center = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(Screen.width, 0f, 0f)).x + 0.5f, 0f);
}
Like the player, this walls also have RigidBody 2D and Box Collider 2D attached to it. My problem is that I'm not able to detect any kind of collision. Not even when I drag the ball up to the walls. Mine intend with this script is detect if, while dragging, you touched the walls. By doing that, I'll be able to call my game state "GameOver" and end the game.
Any idea about WHY, I'm not able to detect this collisions? I'm sure that the walls are in the right position and the ball is indeed touching the walls.
Are you just asking how to detect a collision? Make sure all of your objects (the walls and the player object) have Collider2D components. On those colliders, set IsTrigger to true. Then in your player controller:
void OnTriggerEnter2D(Collider2D other) {
// check if "other" is a wall
if (other.transform.GetComponent<Wall>())
this.gameState = GameStates.GAMEOVER;
}
Note that you need a RigidBody2D on at least one of the collidable GameObjects. Just put a RigidBody2D on everything and don't use gravity.
you didnt wrote how you made screenPoint so here is how just incase
public void OnMouseDown() {
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);