When dragging an object with rigidbody2D it passes through colliders (walls) - unityscript

Ok, so I'm making this game where the user can drag a ball around the screen, but it's not supposed to leave the play area. I'm getting the following problem though, when I push it towards the colliders it bounces back, and if I push too hard it simply goes off screen (I need to make it do not go off screen. the user is free to drag it all over the place, but within the screen of course).
any tips on how I could solve this issue?
Here is the code for dragging which I'm using:
using UnityEngine;
using System.Collections;
public class CircleManager : MonoBehaviour {
private bool dragging = false;
private Vector3 screenPoint;
private Vector3 offset;
// Pressionando
void OnMouseDown()
{
dragging = true;
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
// Arrastando
void OnMouseDrag()
{
Vector3 cursorPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(cursorPoint) + offset;
//i tried with both below.
//transform.position = cursorPosition;
transform.GetComponent<Rigidbody2D>().MovePosition(cursorPosition);
}
// Soltando
void OnMouseUp()
{
dragging = false;
}
}
Thanks!

You could try to do something like,
if( transform.position.x > xMaxPos )
{
transform.position.x = new Vector3( xMaxPos, transform.position.y, transform.position.z );
}
You could set up for each min and max. Then when you create the xMaxPos variables, create them like:
[serializeField]
private float xMaxPos;
That way they will appear in the inspector and you can tweak their values as you please. You could also throw in an offset that's the width of the ball i.e.
transform.position.x = new Vector3( xMaxPos - transform.localscale.x/2, transform.position.y, transform.position.z );

Try using velocity
public class CircleManager : MonoBehaviour {
private bool dragging = false;
private Vector3 screenPoint;
private Vector3 offset;
public float speed = 5.0f;
// Pressionando
void OnMouseDown()
{
dragging = true;
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(ToDepth(Input.mousePosition, transform.position.z));
offset = gameObject.transform.position - cursorPosition;
}
// Arrastando
void OnMouseDrag()
{
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(ToDepth(Input.mousePosition, transform.position.z)) + offset;
Vector3 direction = (transform.position - cursorPosition).normalized;
transform.GetComponent<Rigidbody2D>().velocity = direction * speed * Time.deltaTime;
}
// Soltando
void OnMouseUp()
{
dragging = false;
}
Vector3 ToDepth(Vector3 value, float depth)
{
return new Vector3(value.x, value.y, depth);
}
}
Few things to note:
You don't have to write out gameObject.transform.position i see you did that a few times, as well as calling transform... directly. Its both the same thing, so you don't need the gameObject part.
Also your getting the screenPoint of the transform, then using the z value of that later on, which doesn't really make much sense to me.
Anyways, i don't see why this shouldn't work for you, i haven't tested it though.

Related

Not able to Shoot in the direction of the hand

I have designed a model in blender and imported in Unity and applied ThirdPersonController, ThirdPersonCharacter, ThirdPersonUserControl on it and got animation y following the guidelines, now i have created a script for shooting the bullets and attached it to the rigged hand/gun. But whenever i click "Fire1" the bullet is getting shooted in other direction..
I want when i move the mouse, the hand should move in the direction of the mouse + body should rotate in the direction of the mouse (if on backside) and when i left click, it should fire a bullet in the direction of the mouse(one at a time).
Video for better understanding - http://tinypic.com/r/34yohli/9
I tried a script, but its not following the way i want.
Shoot.js
#pragma strict var projectile : GameObject;
var fireRate = 0.5;
private var nextFire = 0.0;
var shotDelay = .5;
function Update ()
{
if (Input.GetButton ("Fire1") && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
var clone = Instantiate (projectile, transform.position, transform.rotation);
}
}
MouseMovement.cs
using UnityEngine;
using System.Collections;
public class MouseMovement : MonoBehaviour
{
public float speed = 1.5f;
private Vector3 target;
void Start()
{
target = transform.position;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
target.x = transform.position.x;
}
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
}
To detect the movement of the mouse you should use the Input.GetAxis("Mouse X") or Input.GetAxis("Mouse Y"). If you want the camera to move with the character you can set it as a child of the character. You can check the MouseLook Script for more info.

Converting from Matrix4 to Vec3,Quaternion,Vec3 and back again

Libgdx uses a Matrix4 to express the world space position, rotation and scaleing of objects.
As I am animating these objects a lot in my code I wish to convert them to a format that keeps Position, Rotation and Scale Separate.
This makes it easier to interpolate correctly in order to animate them.
I am storing the Scale and Position both as Vector3s.
And the rotation as a Quaternion.
Here is my class that stores these 3 and converts two and from a Matrix4;
public class PosRotScale {
private static String logstag="ME.PosRotScale";
Vector3 position = new Vector3();
Quaternion rotation = new Quaternion();
Vector3 scale = new Vector3(1f,1f,1f);
public PosRotScale(Vector3 position, Quaternion rotation, Vector3 scale) {
super();
this.position = position;
this.rotation = rotation;
this.scale = scale;
}
public PosRotScale(Matrix4 setToThis) {
this.setToMatrix(setToThis);
}
#Override
public String toString(){
Vector3 axis = new Vector3();
float angle = rotation.getAxisAngle(axis);
String stateAsString = "["+position.x+","+position.y+","+position.z+"]"
+ "["+axis.x+","+axis.y+","+axis.z+","+angle+"]"
+ "["+scale.x+","+scale.y+","+scale.z+"]";
return stateAsString;
}
public void setToMatrix(Matrix4 lastLocation) {
lastLocation.getTranslation(position);
lastLocation.getRotation(rotation);
lastLocation.getScale(scale);
}
public PosRotScale setToRotation(float i, float j, float k, float angleInDeg) {
rotation.set(new Vector3(i,j,k), angleInDeg);
return this;
}
public PosRotScale setToPosition(Vector3 newposition) {
position = newposition.cpy();
return this;
}
public PosRotScale setToScaling(Vector3 newscale) {
scale = newscale.cpy();
return this;
}
public Matrix4 createMatrix() {
return new Matrix4(position,rotation.nor(),scale);
}
}
(I apologise for the snippet above having a "run as" and being interpreted as javascript - I didn't see a option in the code snippet box for Java)
Anyway, in order to test if this was working I created a test state and converted to and from it.
Unfortunately the values clearly didn't match.
I expected the rotation to be off a bit (seems to be the nature of rotations) but scale is clearly wayyyy of. Any pointers as to what I am doing wrong?
Test code;
PosRotScale startScaleAndRotation = new PosRotScale();
startScaleAndRotation.setToPosition(new Vector3(30f, 40f, 50f));
startScaleAndRotation.setToRotation(0f, 0f, 1f, 45);
startScaleAndRotation.setToScaling(new Vector3(0.5f, 2.5f,0.5f));
Gdx.app.log(logstag, " setting to: "+startScaleAndRotation.toString());
Matrix4 test = startScaleAndRotation.createMatrix();
PosRotScale test2 = new PosRotScale(test);
Gdx.app.log(logstag, " check after conversion: "+test2.toString());
Results in:
setting to: [30.0,40.0,50.0][0.0,0.0,0.99999994,45.000004][0.5,2.5,0.5]
check after conversion: [30.0,40.0,50.0][0.0,0.0,1.811493,35.83953][1.8027757,1.8027754,0.5]

Animate/move/translate/tween image in Unity 4.6 from C# code

How can I move/animate/translate/tween an Image from position A to position B using C# code in Unity 4.6?
Assuming Image is a GameObject, so it could be a Button or whatever.
There has to be a one-liner for this, right? I've been googling for a while but all I can see out-of-the-box is stuff done in Update, and I firmly believe doing stuff in Update is not a fast way of scripting things.
maZZZu's method will work, however, if you do NOT want to use the Update function, you can use an IEnumerator/Coroutine like so…
//Target object that we want to move to
public Transform target;
//Time you want it to take before it reaches the object
public float moveDuration = 1.0f;
void Start ()
{
//Start a coroutine (needed to call a method that returns an IEnumerator
StartCoroutine (Tween (target.position));
}
//IEnumerator return method that takes in the targets position
IEnumerator Tween (Vector3 targetPosition)
{
//Obtain the previous position (original position) of the gameobject this script is attached to
Vector3 previousPosition = gameObject.transform.position;
//Create a time variable
float time = 0.0f;
do
{
//Add the deltaTime to the time variable
time += Time.deltaTime;
//Lerp the gameobject's position that this script is attached to. Lerp takes in the original position, target position and the time to execute it in
gameObject.transform.position = Vector3.Lerp (previousPosition, targetPosition, time / moveDuration);
yield return 0;
//Do the Lerp function while to time is less than the move duration.
} while (time < moveDuration);
}
This script will need to be attached to the GameObject that you would like to move. You will then need to create another GameObject in the scene that will be your Target…
The code is commented but if you need clarification on something just post a comment here.
If you want to do the movement yourself you can use something like this:
public Vector3 targetPosition = new Vector3(100, 0, 0);
public float speed = 10.0f;
public float threshold = 0.5f;
void Update () {
Vector3 direction = targetPosition - transform.position;
if(direction.magnitude > threshold){
direction.Normalize();
transform.position = transform.position + direction * speed * Time.deltaTime;
}else{
// Without this game object jumps around target and never settles
transform.position = targetPosition;
}
}
Or you can download for example DOTween package and just start the tween:
public Vector3 targetPosition = new Vector3(100, 0, 0);
public float tweenTime = 10.0f;
void Start () {
DOTween.Init(false, false, LogBehaviour.Default);
transform.DOMove(targetPosition, tweenTime);
}

Position of GUI.Label in Unity3D

I have a huge (but probably simple) problem. I want to display score. I'm using GUI.Label. When I scale GUI.Label. I want to set position of text. I work on Android, so there are many resolutions and aspect ratios, and I have problem with giving it a precise position.
The "GAME OVER" text is sprite. I tried to set position as half of screen height. It works on some devices, but it doesn't work on devices with highest resolution (1280x720). When I set 400px from top it works, but it doesn't make any sense. Is there any tip for this? I want to display score like here.
My code:
private string labelText;
public Font fontxd;
public Vector2 sizexde;
/*[HideInInspector]*/public GUIStyle styl;
public int p,hp;
static GameObject g1;
static punkt playerScript;
static float virtualWidth = 640.0f;
static float virtualHeight = 400.0f;
static Rect rece;
static Vector3 v3;
public Matrix4x4 matrixs;
static float guiRatio=Screen.width/640;
static float XD=0;
void Start() //1280x720
{
if (Screen.width > Screen.height) {
XD=Screen.width/2;
}
else{//if( Screen.height>Screen.width ){
XD=Screen.height/2;
}
rece=new Rect(10,XD, Screen.width,1);
v3 = new Vector3 (Screen.width / virtualWidth, Screen.width / virtualWidth , 1.0f);
matrixs = Matrix4x4.TRS (Vector3.zero, Quaternion.identity, v3);
g1 = GameObject.Find("XDXDX2");
playerScript = g1.GetComponent<punkt>();
}
void OnGUI()
{
p = playerScript.punkty;
hp = playerScript.hpunkty;
labelText = "Height: " + Screen.height+"-"+Screen.height/2 + "\nWidth: " + Screen.width + "-"+Screen.width/2 ;
GUI.matrix = matrixs;
styl.normal.textColor = Color.black;
styl.font = fontxd;
styl.fontSize = 70;
GUI.Label (rece, labelText, styl);
}
GameObject > CreateOther > GUIText
Edit settings in inspect as shown below:
Now your label's position should be resolution independent.

How to control an animation by touch position along a path in Unity3D?

I have a GameObject that I want to animate along a specific path/curve, but the animation should be controlled by mouse/touch position. So when I touch/click on the GameObject and move the finger/mouse on/near the path (or maybe its easier to just move down) the GameObject should follow its defined path.
I like iTween, but I think it is not possible to find a solution using it here, right?
edit: added image:
It's quite a simpler task than what you might think.
Basically it's a question of remapping a function (that takes the input as parameter) to another function (that express a position along a path).
There are several ways of doing that, depending on the precise effect you want to implement.
The most important choices you have to take are:
How the describe the path/curve
How to handle input
Example
For the path an easy and flexible way is to use some sort of spline curves, such as cubic Bézier curve. It's easy to implement and Unity3D provides built-in functions to draw them. Have a look at Handles.DrawBezier.
Basically a Bézier function takes as input a parameter t in the domain [0,1] and return as a result a point in the space (2D or 3D as you prefer). B(0) gives the point at the begin of the curve, B(1) the end point. (Side note: the function is not linear so in the general case incrementing at a constant rate t doesn't produce a movement at constant speed along the curve. This paper might be useful).
For what concern the input the simpler solution that comes up to my mind is the following:
Accumulate somewhere the vector describing the offset from the position when the touch started to the current touch position. (Here's how to handle touches, have a look at deltaPosition).
Something like:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
offsetFromStartPos += Input.GetTouch(0).deltaPosition;
}
Let's say you want to swipe up/down your finger for moving forward/back an object along a path.Choose a "travel" distance (the domain of the input function) for your finger in order to complete the movement along the curve and normalize the offset using such distance in order to remap the input into the [0,1] domain.
float t = offsetFromStartPos.y / maxDistanceAlongYAxis;
Vector3 pos = CalculateBezier(t);
transform.position = pos;
It's just an hint to put you in the right direction.
I tried with keyboard and its working fine,
but not with mouse or touch
using System;
using UnityEngine;
public class Collector : MonoBehaviour
{
public Transform startPoint;
public Transform middlePoint;
public Transform endPoint;
public float curveSpeed = 0.5f;
//public float speed = 0f;
private int _direction = 1;
private bool _isObjectSelected;
private Vector3 _mouseLastPosition;
private float _journeyLength;
private Vector3 _offsetPos;
private float _currentTime = 0;
private void Start()
{
_journeyLength = Vector3.Distance(startPoint.position,
endPoint.position);
UpdateJourney(0);
}
private void OnMouseDown()
{
if (_isObjectSelected)
return;
_offsetPos = Vector3.zero;
_mouseLastPosition = Input.mousePosition;
_isObjectSelected = true;
}
private void OnMouseUp()
{
_isObjectSelected = false;
}
private void OnMouseExit()
{
_isObjectSelected = false;
}
private void OnMouseDrag()
{
if (_isObjectSelected)
{
Debug.LogError("Mouse drag");
Vector3 currentPosition = Input.mousePosition;
_offsetPos += currentPosition - _mouseLastPosition;
float distCovered = _offsetPos.y / _journeyLength;
UpdateJourney(distCovered);
_mouseLastPosition = currentPosition;
}
}
private void UpdateJourney(float time)
{
if (time < 0)
time = 0;
else if (time > 1)
time = 1;
_currentTime = time;
transform.position =
QuadraticCurve(startPoint.position,
middlePoint.position,
endPoint.position,
_currentTime);
transform.rotation = Quaternion.Euler(
new Vector3(0, 0,
QuadraticCurve(0, 45, 90, _currentTime)));
}
private void Update()
{
// moving on path using keyboard input
float direction = Input.GetAxisRaw("Horizontal");
if (Math.Abs(direction) > 0.1f)
{
_currentTime += Time.deltaTime * curveSpeed * direction;
UpdateJourney(_currentTime);
}
}
private static Vector3 Lerp(Vector3 start, Vector3 end, float time)
{
return start + (end - start) * time;
}
private static Vector3 QuadraticCurve(Vector3 start, Vector3 middle, Vector3 end, float time)
{
Vector3 point0 = Lerp(start, middle, time);
Vector3 point1 = Lerp(middle, end, time);
return Lerp(point0, point1, time);
}
private static float QuadraticCurve(float start, float middle, float end, float time)
{
float point0 = Mathf.Lerp(start, middle, time);
float point1 = Mathf.Lerp(middle, end, time);
return Mathf.Lerp(point0, point1, time);
}
}

Resources