Rotating and moving 2D-objects on mouse drag - c#

I wanted to recreate a game (tangram) where you can rotate and move the pieces.
The game can be found on this website: https://de.mathigon.org/tangram
I have found scripts for rotating and moving the object (a png-file) but when I add the two scripts togehter the object moves randomly around. As programme I use Unity.
The script for moving:
using UnityEngine;
using System.Collections;
public class DragDropScript : MonoBehaviour {
private Vector3 screenPoint;
private Vector3 offset;
void OnMouseDown()
{
Debug.Log("mouse down");
screenPoint = Camera.main.WorldToScreenPoint(transform.position);
offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
void OnMouseDrag()
{
Debug.Log("mouse drag");
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
transform.position = curPosition;
}
}
And the script for rotating
using UnityEngine;
using System.Collections;
public class ObjectRotator : MonoBehaviour
{
private float _sensitivity;
private Vector3 _mouseReference;
private Vector3 _mouseOffset;
private Vector3 _rotation;
private bool _isRotating;
void Start ()
{
_sensitivity = 0.4f;
_rotation = Vector3.zero;
}
void Update()
{
if(_isRotating)
{
// offset
_mouseOffset = (Input.mousePosition - _mouseReference);
// apply rotation
_rotation.z = -(_mouseOffset.x + _mouseOffset.y) * _sensitivity;
// rotate
transform.Rotate(_rotation);
// store mouse
_mouseReference = Input.mousePosition;
}
}
void OnMouseDown()
{
// rotating flag
_isRotating = true;
// store mouse
_mouseReference = Input.mousePosition;
}
void OnMouseUp()
{
// rotating flag
_isRotating = false;
}
}
So far I struggle with Unity. In my bachelor-thesis I got a HoloLens2 and could use the MRTK which really helped developing a application. Thank you in advanced.
At the end the game should be built as WebGL.

The random result is probably due to trying to move and rotate the object at the same time. An easy fix for this would be to move on left mouse button and rotate with right click, or vice versa. You can use Input.GetMouseButton to check if a button is pressed and insert checks in the script to only move OR rotate.
More complicated solutions would involve some kind of "widget" that is dragged, that way you can have different widgets for drag and rotate.
I would also recommend learning a bit of geometry and trigonometry to be able to understand the posted scripts. Copying scripts of the internet will only get you so far.

Related

Unity Rotating GameObject around player in top down 3d

I am new to unity and my research on this issue isn't getting me any results.
I am trying to get a GameObject rotate around the Player in the direction of the mouse.
and the class I have for the RotatePoint
using UnityEngine;
public class Launcher : MonoBehaviour
{
private Camera mainCamera;
private Vector3 mousePos;
private void Start()
{
mainCamera = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>();
}
private void Update()
{
faceMouse();
}
private void faceMouse()
{
mousePos = mainCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
Input.mousePosition.y, Camera.main.nearClipPlane));
Vector3 distence = mousePos - transform.position;
Quaternion rotation = Quaternion.LookRotation(distence);
transform.rotation = Quaternion.RotateTowards(transform.rotation, rotation, 1);
}
}
Player
Main Camera
Rotate Point
Projectile Transform
right now it works EXCEPT for its 90 degrees off where it should be.
I watched a few tutorials on this but they all seem to be for 2D which apparently doesn't convert so nicely to 3D

FPS Projectile firing from the wrong place

I'm trying to make a basic FPS game in Unity and I'm having an issue where the projectiles I shoot won't instantiate in the right place. From what I can tell, the projectile instantiates in roughly the same position relative to the player regardless of where I look (that position being a little to the left of the starting angle of the player).
Here's a 20 second video demonstration of what I'm talking about.
https://youtu.be/WLVuqUtMqd0
Even when I'm facing the exact opposite direction of where the projectile usually instantiates it still spawns in the same place, which means the projectile ends up spawning behind the player and hitting the player.
I tried using Debug.DrawRay() to see if maybe the firepoint itself is wrong (which would be shown by the ray starting somewhere other than the gun barrel). However it seems like the starting point of the ray is correct every time.
I'm not sure if this is related to the issue above, but I have noticed that the ray direction is wrong if I'm looking a little below the horizon. It seems like the projectile's direction is correct regardless though.
Ray directions when looking slightly above the horizon vs. lower
Here's my code for intantiating/shooting the projectile. I think the most relevant parts are probably shootProjectile() and instantiateProjectile(). This script is attached to the player character.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooting : MonoBehaviour
{
public Camera cam;
public GameObject projectile;
public Transform firePoint;//firePoint is set to the end of the barrel.
public float projectileSpeed = 40;
//private var ray;
private Vector3 destination;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//var ray = cam.ViewportPointToRay(new Vector3(0.5f,0.5f,0));
//Debug.DrawRay(ray.origin, ray.direction);
if(Input.GetButtonDown("Fire1")) {
//player is shooting
ShootProjectile();
}
}
void ShootProjectile() {
Ray ray1 = cam.ScreenPointToRay(Input.mousePosition);
//Debug.Log(ray.direction);
RaycastHit hit;
if(Physics.Raycast(ray1, out hit))//checking whether the player is going to hit something
{
destination = hit.point;
}
else {
destination = ray1.GetPoint(1000);
}
Debug.DrawRay(firePoint.position, destination, Color.white, 10f);
InstantiateProjectile(firePoint);
}
void InstantiateProjectile(Transform firePoint) {
var projectileObj = Instantiate (projectile, firePoint.position, Quaternion.identity) as GameObject;//projectile is instantiated
projectileObj.GetComponent<Rigidbody>().velocity = (destination - firePoint.position).normalized * projectileSpeed;//projectile is set in motion
}
}
Here's the location of firePoint.
firePoint (i.e. where the projectile should instantiate)
I would appreciate any help on this, as I've been trying to fix it (on and off) for several days, and really have no idea what the problem is.
Edit: Here's my player movement script(s) as well. The first one is PlayerController.cs, and it converts the player's inputs into the appropriate movement vectors and camera rotation. It then calls methods from PlayerMotor.cs, which actually performs the movements.
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(PlayerMotor))]
public class PlayerController : MonoBehaviour
{
[SerializeField]
public float speed = 10f;
[SerializeField]
private float lookSens = 3f;
private PlayerMotor motor;
void Start() {
motor = GetComponent<PlayerMotor>();
//Debug.Log("PlayerControllerStart");
Cursor.lockState = CursorLockMode.Locked;
}
void Update() {
//Debug.Log("PlayerControllerUpdate");
//calculate movement velocity as 3D vector.
float xMov = Input.GetAxisRaw("Horizontal");
float zMov = Input.GetAxisRaw("Vertical");
Vector3 movHorizontal = transform.right * xMov;
Vector3 movVertical = transform.forward * zMov;
Vector3 velocity = (movHorizontal + movVertical).normalized * speed;
motor.move(velocity);
//speed*=(float)1.15;
//rotation
float yRot = Input.GetAxisRaw("Mouse X");
Vector3 rotation = new Vector3 (0f, yRot, 0f) * lookSens;
motor.rotate(rotation);
float xRot = Input.GetAxisRaw("Mouse Y");
Vector3 cameraRotation = new Vector3 (xRot, 0f, 0f) * lookSens;
motor.rotateCamera(cameraRotation);
if (Input.GetKeyDown(KeyCode.Space) == true && motor.isGrounded()) {
motor.canJump=true;
}
if (Input.GetKey(KeyCode.W) == true) {
motor.accel=true;
}
else{
motor.accel=false;
}
}
}
PlayerMotor:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PlayerMotor : MonoBehaviour
{
[SerializeField]
private Camera cam;
private Vector3 velocity = Vector3.zero;
private Vector3 rotation = Vector3.zero;
private Vector3 cameraRotation = Vector3.zero;
private Vector3 jumpVector = new Vector3 (0f, 5f, 0f);
private PlayerController pc;
private Rigidbody rb;
public bool canJump;
public bool accel;
public float acceleration;
int jumpCount;
void Start() {
rb = GetComponent<Rigidbody>();
pc = GetComponent<PlayerController>();
canJump=false;
jumpCount=0;
accel=false;
//acceleration = 1.0;
//distToGround = collider.bounds.extents.y;
//Debug.Log("PlayerMotorStart");
}
//sets velocity to a given movement vector.
public void move(Vector3 _velocity) {
velocity = _velocity;
}
public void rotate(Vector3 _rotation) {
rotation = _rotation;
}
public void rotateCamera(Vector3 _cameraRotation) {
cameraRotation = _cameraRotation;
}
public bool isGrounded() {
return Physics.Raycast(transform.position, -Vector3.up, (float)2.5);
}
public void jump() {
rb.AddForce(transform.up * 250f);
//Debug.Log("Jump"+jumpCount);
jumpCount++;
canJump=false;
}
void FixedUpdate() {
performMovement();
performRotation();
if (canJump) {
jump();
}
//Debug.Log("PlayerMotorUpdate");
if(accel&&pc.speed<20f&&isGrounded())
{
//Debug.Log("W Pressed");
pc.speed*=(float)1.005;
}
else if(!accel) {
pc.speed=7f;
}
}
void performMovement() {
if(velocity != Vector3.zero) {
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
//Debug.Log("Movement");
}
}
void performRotation() {
rb.MoveRotation(rb.rotation * Quaternion.Euler(rotation));
if(cam != null) {
cam.transform.Rotate(-cameraRotation);
}
}
}
Here are some pictures of my projectile prefab as well.
To solve one first confusion: The method Debug.DrawRay takes as paramters
a start position
a ray direction(!)
You are passing in another position which is not what you want.
This might only work "accidentally" as long as you stand on 0,0,0 so maybe it wasn't that notable but the debt ray definitely points into a wrong direction.
Rather do e.g.
Debug.DrawRay(firePoint.position, destination - firePoint.position, Color.white, 10f);
Or instead rather use Debug.DrawLine which rather actually takes
start position
end position
Then you don't need to calculate the direction first
Debug.DrawLine(firePoint.position, destination, Color.white, 10f);
Then I suspect the following is happening: The spawned projectileObj actually is placed correctly but it is the visuals inside that projectile prefab that have a local offset against the parent prefab root.
Since you always spawn the projectile in world rotation Quaternion.identity that offset stays the same no matter where you look.
I guess a simple fix would already be to also apply the same rotation like
var projectileObj = Instantiate (projectile, firePoint.position, firePoint.rotation);

How to launch an instantiated object in a certain direction from the center of the screen based on the mouse pointer position?

I am creating a simple game where you are locked in the center of the screen and must shoot things as they move toward you. The problem I am currently facing is that I can not launch a bullet in the direction of my mouse cursor. Currently, my code looks like this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour {
PlayerScript playerScript;
public float xVel;
public float yVel;
public float direction;
private void Awake()
{
playerScript = FindObjectOfType<PlayerScript>();
//playerScript.AngleDeg is the direction the player is facing (based on mouse cursor)
transform.rotation = Quaternion.Euler(0, 0, playerScript.AngleDeg);
direction = transform.rotation.z;
//from the unit circle (x = cos(theta), y = sin(theta)
xVel = Mathf.Cos(direction * Mathf.PI);
yVel = Mathf.Sin(direction * Mathf.PI);
}
void Update () {
transform.position += new Vector3(xVel,yVel,0);
}
}
currently, when I run the code, the bullet shoots at an angle which is at the direction that is correct when the player is orientated sideways, but when orientated vertically is a full 45 degrees off.
Attach this as a component to your instantiated bullet object and it should work.
Transform playerTransform;
float bulletSpeed;
Vector3 directionToShoot
void Start()
{
playerTransform = FindObjectOfType<PlayerScript>().gameObject.transform;
bulletSpeed = 3f;
//Direction for shooting
directionToShoot = playerTransform.forward - Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void Update()
{
//shoot
transform.Translate(directionToShoot * bulletSpeed * Time.deltaTime);
}

Restricting cursor to a radius around my Player

I am currently working on an multiplayer shooter game. Basicly atm you play as a cube and you have your hand(red square) following the cursor ingame.
I want to restrict the cursor movement to a perfect circle around my player sprite.
See attached picture for clarification.
https://imgur.com/TLliade
Following script is attached to the "Hand" (red square).
public class Handscript : MonoBehaviour
{
void Update()
{
Cursor.visible = false;
Vector3 a = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
a.Set(a.x, a.y, transform.position.z);
transform.position = Vector3.Lerp(transform.position, a, 1f);
}
}
Now I want to restrict cursor movement inside my radius that is a public transform attached to my Player prefab like this:
//Hand radius
public float radius;
public Transform centerRadius;
I am hard stuck and new to coding overall and I could use a push in the right direction.
Basicly the same question is asked here if I am being to unclear:
https://answers.unity.com/questions/1439356/limit-mouse-movement-around-player.html
EDIT: My goal in the end is to have similar hand movement as in the legendary "Madness Interactive" game, found here:
https://www.newgrounds.com/portal/view/118826
EDIT2: It might be impossible to lock the cursor inside the radius circle. Is it possible to just have the GameObject "Hand" locked inside this radius?
EDIT3: This is the code I use and it works like a charm:
using System;
using UnityEngine;
public class Handscript : Photon.MonoBehaviour
{
[SerializeField] private GameObject Player2; //Drag your player game object here for its position
[SerializeField] private float radius; //Set radius here
public new PhotonView photonView; //Never mind this if its not a photon project
private void Start()
{
Cursor.visible = false;
}
void Update()
{
if (photonView.isMine) //Never mind this if statement if it isnt a photon project
{
Vector3 cursorPos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
Vector3 playerPos = Player2.transform.position;
Vector3 playerToCursor = cursorPos - playerPos;
Vector3 dir = playerToCursor.normalized;
Vector3 cursorVector = dir * radius;
if (playerToCursor.magnitude < cursorVector.magnitude) // detect if mouse is in inner radius
cursorVector = playerToCursor;
transform.position = playerPos + cursorVector;
}
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
UnityEditor.Handles.DrawWireDisc(transform.parent.position, Vector3.back, radius); // draw radius
}
#endif
}
Get vector from the player to the cursor:
Vector3 playerToCursor = cursorPos - playerPos;
Normalize it to get the direction:
Vector3 dir = playerToCursor.normalized;
Multiply direction by your desired radius:
Vector3 cursorVector = dir * radius;
Add the cursor vector to the player position to get the final position:
Vector3 finalPos = playerPos + cursorVector;

Triggering a script on another object when Clicking and Dragging in Unity

I am doing a 2D project where I've added a sprite as a button to shoot. This button works fine. The script attached is: (I added a box collider to the sprite)
using UnityEngine;
using System.Collections;
public class ClickScript : MonoBehaviour {
public shootTest _shooterScript;
// Use this for initialization
void Start () {
}
void LoadScript()
{
_shooterScript.ShootRock();
}
// Update is called once per frame
void Update () {
if(Input.GetMouseButtonDown(0)){
Vector2 mousePosition = new Vector2();
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Collider2D hitCollider = new Collider2D();
hitCollider = this.collider2D;
hitCollider = Physics2D.OverlapPoint(mousePosition);
Debug.Log("mouse pos "+mousePosition.x+" y "+mousePosition.y+" ");
if(hitCollider){
LoadScript();
Debug.Log("Hit "+hitCollider.transform.name+" x"+hitCollider.transform.position.x+" y "+hitCollider.transform.position.y);
}
}
}}
Then I added a crosshair to be able to calculate a direction to aim. Here is the script to click and drag the object. Circle Colider 2D on this object.
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(MeshCollider))]
public class Aim : MonoBehaviour
{
private Vector3 screenPoint;
private Vector3 offset;
void OnMouseDown()
{
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
void OnMouseDrag()
{
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint)+offset;
this.transform.position = curPosition;
}
}
When I add this aiming script and click on the crosshair to drag it, the shoot script goes off.
I'm very new to unity so I'm assuming it is something simple. Thanks for the help.
I changed the update function in the click script to
void Update () {
if(Input.GetMouseButtonDown(0)){
Vector2 mousePosition = new Vector2();
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if(this.collider2D.OverlapPoint(mousePosition)){
LoadScript();
}
}
So it only triggers when that specific object is clicked. Maybe there is a cleaner way, but this worked.

Categories

Resources