unity How to swipe jump motion using add force. - unity3d

I have a ball standing on a platform and i have written code so that every time i swipe up the ball jumps from one platform to another depending on the force of the swipe. At the moment my platforms are just placed in position by myself and i dont have a script for their random generation. The only script i have is on the player for swiping and moving forward.
Currently im making this motion by adding force in two directions, up and forward to create the projectile motion. Its working like its supposed too, but the motion is too slow. I want it to sort of move faster. Iwe tried playing with the forces as well as the mass of the ball. They do make a difference, but I still want the ball to move some what faster.
Is adding force the best way to do this? Or would you recommend a different way?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwipeScript : MonoBehaviour {
public float maxTime;
public float minSwipeDist;
float startTime;
float endTime;
Vector3 startPos;
Vector3 endPos;
float swipeDistance;
float swipeTime;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
startTime = Time.time;
startPos = touch.position;
}
else if (touch.phase == TouchPhase.Ended)
{
endTime = Time.time;
endPos = touch.position;
swipeDistance = (endPos - startPos).magnitude;
swipeTime = endTime - startTime;
if (swipeTime < maxTime && swipeDistance > minSwipeDist)
{
swipe();
}
}
}
}
public void swipe()
{
Vector2 distance = endPos - startPos;
if (Mathf.Abs(distance.y) > Mathf.Abs(distance.x))
{
Debug.Log("Swipe up detected");
jump();
}
}
private void jump()
{
Vector2 distance = endPos - startPos;
GetComponent<Rigidbody>().AddForce(new Vector3(0, Mathf.Abs(distance.y/5), Mathf.Abs(distance.y/5)));
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "Cube (1)") {
Debug.Log("collision!");
GetComponent<Rigidbody>().velocity = Vector3.zero;
GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
}
}
}

I was writing my answer when I noticed #Fredrik comment: pretty much all he said was in what I wrote so I'll just skip it ! (I also do not recommend increasing Time.timeScale)
The other way you could move your ball would be using ballistic equations and setting your RigidBody to Kinematic. This way you will be able to control the ball speed through code using RigidBody.MovePosition() and still get OnCollision[...] events.
Also as a side note I do not recommend using collision.gameObject.name for collision object checking but rather tagging your cubes or even setting their layer to a specific one (but I guess this may be temporary code of yours ;) ).
Hope this helps,

Either pass ForceMode.VelocityChange as a second parameter to AddForce, or make sure you divide your vector by Time.fixedDeltaTime (which has the effect of multiplying it because Time.fixedDeltaTime will be less than 1).

Related

Jittery movement with falling object moving back and forth horizontally

I've got a falling object, which i want to move back and forth horizontally while falling.
While i've manage to do this, i'm getting a jittery movement while this happens. When the object falls without horizontal movement, theres no jittery movement.This is also the case if the object just moves horizontally without falling.
I'm currently using rigidbody2d.velocity to move it horizontally and have tried using transform.position and translate but didn't see any difference in smoother movement.
Jittery Movement GIF
So clearly theres an issue with combine the two movements together, but i can't work out how to remedy this in order to make it a smooth movement.
Object Inspector Image
Here's the object code for it's movement:
public float verticalSpeed = 7f;
private Rigidbody2D object_RB;
private int moveHorizontal;
private int horizontalSpeed;
void Start()
{
object_RB = GetComponent<Rigidbody2D>();
moveHorizontal = Random.Range(1, 3);
horizontalSpeed = Random.Range(4, 7);
}
void Update()
{
if (transform.position.y <= -10f)
{
Destroy(gameObject);
}
if (transform.position.x < -1.7f)
{
moveHorizontal = 1;
}
else if (transform.position.x > 1.7f)
{
moveHorizontal = 2;
}
transform.position -= transform.up * Time.deltaTime * verticalSpeed;
}
void FixedUpdate()
{
if (moveHorizontal == 1)
{
object_RB.velocity = new Vector2(horizontalSpeed, 0);
}
else if (moveHorizontal == 2)
{
object_RB.velocity = new Vector2(-horizontalSpeed, 0);
}
}
I'm stuck with this and would appreciate some input to fix this movement.
EDIT - I've tried setting the Interpolate property of the rigidbody to Interpolate or Extrapolate and had no luck. If i set it to Interpolate, the horizontal movement slows down drastically, to a point where it doesn't seem like its moving horizontally at all. Changing it to Extrapolate actually increases the jittery effect.

How to move 2d Rigidbody Smoothly to Mouse on Click

Vector2 mousePos = Input.mousePosition;
// motion core
if (GameObject.Find("Camera").GetComponent<room>().playerNum == 1)
{
if (Input.GetMouseButtonDown(0))
{
// move script not working
}
}
So, I have mostly every possible solution I could find but none of them worked. I cannot get it to smoothly move with AddForce because I could not figure out a working algorithm to make the force move toward the MousePosition.
The position you're getting out of Input.mousePosition are the coordinates on the screen, not the position in the world. To transform between the two, you can use Camera.ScreenToWorldPoint().
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Input.mousePosition
mousePos = new Vector3(mousePos.x, mousePos.y, Camera.main.nearClipPlane)
Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3())
// move script
}
You might need to edit the z coordinate in the mousePos to the current transform.position.z of the object you're trying to move, or another value that makes most sense here. It acts as a kind of wall, where it'll create the point exactly that far from the camera on your mouse position. This should be a lot cheaper than raycasting, and still works if there's nothing to hit where you're clicking.
I have a script that did this same movement to the handle of a wrecking ball, but I don't have the code with me at the moment. I can't remember exactly how it worked, but I think the idea was that when the mouse was clicked, drag would be set to a very high number and gravity would be set to 0. Then an extremely strong force would be added to counter the drag so that the object would fly towards the mouse without orbiting. When the mouse was released, the drag and gravity would be set back to normal.
I can't test this at the moment because I'm on a chromebook and my PC with Unity on it is in another building, but this code should do the trick if I don't make any errors.
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
float prevDrag, prevGrav;
bool mousedown;
Plane plane;
Rigidbody2D r;
void Start()
{
r = GetComponent<Rigidbody2D>(); // assuming this script is attached to the object being moved.
plane = new Plane(Vector3.up, Vector3.zero);
}
void Update()
{
if(mousedown)
{
float enter;
if (plane.Raycast(ray, out enter))
{
var hitPoint = ray.GetPoint(enter);
var mouseDir = hitPoint - gameObject.transform.position;
rb.AddForce(mouseDir * 9999999);
}
}
}
void OnMouseDown()
{
mousedown = true;
prevDrag = r.drag;
prevGrav = r.gravity;
r.drag = 99999;
r.gravity = 0;
}
void OnMouseUp()
{
mousedown = false;
r.drag = prevDrag;
r.gravity = prevGrav;
}
}

my character jumps too strong sometimes in unity 2d

My character's jump is working fine in a straight line collider, then I noticed that when every-time my character jumps in a curve shape collider, my jump always turns too strong abnormaly. How can I fix this? I'll provide my initial code for jump movement below.
Here is the img :
Here is jump code:
float checkgroundradius = 0.50f;
public bool isgrounded2;
public Transform grouncheckslot;
public LayerMask LM;
public float JumpPower;
public float movespeed;
Rigidbody2d RB;
void Update () {
if (isgrounded && Input.GetKeyDown(KeyCode.UpArrow))
{
isgrounded = false;
jumping = true;
myanim.SetBool("groundedanim", isgrounded);
myrb.AddForce(new Vector2(0, jumpower));
}
}
void FixedUpdate()
{
isgrounded = Physics2D.OverlapCircle(checkslot.position, groundradius, LM);
myanim.SetBool("groundedanim", isgrounded);
myanim.SetFloat("verticalspeed", myrb.velocity.y);
float move = Input.GetAxis ("Horizontal");
RB.velocity = new Vector 2 (move * movespeed, RB.velocity.y);
}
When jumping up the slope, your Physics2D.OverlapCircle intersects with the slope, thus making isgrounded=true, making you apply more force if the UpArrow is pressed.
Once solution could be to check that your character is not already moving upwards before jumping
if (isgrounded && Input.GetKeyDown(KeyCode.UpArrow) && myrb.velocity.y <= 0.0f)
this way you wont jump again if you are already heading upwards.
Maybe you could play around with a smaller groundradius and/or try moving the checkslot.position in a way that it doesnt intersect with the slope in the same manner.
For jumping people use Rigidbody2D.AddForce with Forcemode.Impulse.
Also, change
if (isgrounded && Input.GetKeyDown(KeyCode.UpArrow))
to
if (Input.GetKeyDown(KeyCode.UpArrow) && myrb.velocity.y == 0)
So you don't need to bool isgrounded
I hope it helps you :)

AI returning to original position

I want my enemy to move back to starting position. He follows me until I get out of his range and then he just stops.
Also i want my skeleton to stop for like 5 sec, and then go back to starting point, any ideas ? I never did anything involving time, exept stopping it.
Here is my script for enemy:
Also here is a screenshoot of inspector on the skeleton: enemy
Here is my script for enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class chase : MonoBehaviour
{
public Transform player;
private Animator anim;
public float LookRadius = 15f;
public Transform enemyStartPos;
// Use this for initialization
void Start()
{
anim = GetComponent<Animator>();
this.enemyStartPos.position = this.transform.position;
}
// Update is called once per frame
void Update()
{
if (!PauseMenu.GameIsPaused)
{
if (Vector3.Distance(player.position, this.transform.position) < 15)
{
Vector3 direction = player.position - this.transform.position;
direction.y = 0;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, Quaternion.LookRotation(direction), 0.1f);
anim.SetBool("isIdle", false);
if (direction.magnitude > 3)
{
this.transform.Translate(0, 0, 0.05f);
anim.SetBool("isWalking", true);
anim.SetBool("isAttacking", false);
}
else
{
anim.SetBool("isAttacking", true);
anim.SetBool("isWalking", false);
}
}
else
{
if (Vector3.Distance(this.enemyStartPos.position, this.transform.position) >1)
{
Vector3 direction = this.enemyStartPos.position - this.transform.position;
direction.y = 0;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, Quaternion.LookRotation(direction), 0.1f);
anim.SetBool("isIdle", false);
if (direction.magnitude > 1)
{
this.transform.Translate(0, 0, 0.05f);
anim.SetBool("isWalking", true);
anim.SetBool("isAttacking", false);
}
}
else
anim.SetBool("isIdle", true);
anim.SetBool("isAttacking", false);
anim.SetBool("isWalking", false);
}
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, LookRadius);
}
}
Before you try to "code" this, think about it in terms of your program design. You have designed and implemented behavior that says "if the bot's position is within X units of the player's position, turn the bot and move it toward the player."
What you describe wanting to do next can be thought of in the same way (which should lead to similar code).. "else, if the bot's position is NOT within X units of the player's position, turn the bot and move it toward [origin]." Note, this means you need to define what [origin] is for the bot. Point being, it makes no difference in the code whether you are moving toward a player or some arbitrary fixed point. The code to move one transform toward another transform is the same.
For "wandering" it's essentially the same thought process: If bot is within X units of [origin] and not following player, pick a random direction and move that way. (better yet, pick a random direction and move that way for some amount of time so your bot doesn't just jitter around origin).

player won't stick on a moving platform

I have created some moving platforms for my game. There's a game object called PlatformPath1 which has children that define the start and end of the platform's cycle and then obviously there's the actual platform which follows the path. The platform moves perfect however, like expected, the player does not move with the platform. How would I get the player to move with the platform?
Here is the code for PlatformPath1
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
public class FollowPath : MonoBehaviour
{
public enum FollowType
{
MoveTowards,
Lerp
}
public FollowType Type = FollowType.MoveTowards;
public PathDefinition Path;
public float Speed = 1;
public float MaxDistanceToGoal = .1f;
private IEnumerator<Transform> _currentPoint;
public void Start()
{
if (Path == null)
{
Debug.LogError("Path cannot be null", gameObject);
return;
}
_currentPoint = Path.GetPathEnumerator();
_currentPoint.MoveNext();
if (_currentPoint.Current == null)
return;
transform.position = _currentPoint.Current.position;
}
public void Update()
{
if (_currentPoint == null || _currentPoint.Current == null)
return;
if (Type == FollowType.MoveTowards)
transform.position = Vector3.MoveTowards (transform.position, _currentPoint.Current.position, Time.deltaTime * Speed);
else if (Type == FollowType.Lerp)
transform.position = Vector3.Lerp(transform.position, _currentPoint.Current.position, Time.deltaTime * Speed);
var distanceSquared = (transform.position - _currentPoint.Current.position).sqrMagnitude;
if (distanceSquared < MaxDistanceToGoal * MaxDistanceToGoal)
_currentPoint.MoveNext();
}
}
And here is the code for the platform
using System;
using UnityEngine;
using System.Collections.Generic;
using System.Collections;
public class PathDefinition : MonoBehaviour
{
public Transform[] Points;
public IEnumerator<Transform> GetPathEnumerator()
{
if(Points == null || Points.Length < 1)
yield break;
var direction = 1;
var index = 0;
while (true)
{
yield return Points[index];
if (Points.Length == 1)
continue;
if (index <= 0)
direction = 1;
else if (index >= Points.Length - 1)
direction = -1;
index = index + direction;
}
}
public void OnDrawGizmos()
{
if (Points == null || Points.Length < 2)
return;
for (var i = 1; i < Points.Length; i++) {
Gizmos.DrawLine (Points [i - 1].position, Points [i].position);
}
}
}
You could add the Player as a child to the platform. That way, when the platform moves, the player will too.
At the end of the movement (or on some user input), you could break the parenting. Here's some code you can try out.
public GameObject platform; //The platform Game Object
public GameObject player; //The player Game Object
//Call this to have the player parented to the platform.
//So, say for example, you have a trigger that the player steps on
//to activate the platform, you can call this method then
void AttachPlayerToPlatform () {
player.transform.parent = platform.transform;
}
//Use this method alternatively, if you wish to specify which
//platform the player Game Object needs to attach to (more useful)
void AttachPlayerToPlatform (GameObject platformToAttachTo) {
player.transform.parent = platformToAttachTo.transform;
}
//Call this to detach the player from the platform
//This can be used say at the end of the platform's movement
void DetachPlayerFromPlatform () {
player.transform.parent = null;
}
If you were to stand on a moving platform in the real world, the reason you would move with the platform is because of the friction between the platform and your feet. If the platform were covered in ice, you might not move with the platform if it begins its motion while you're on it!
Now we can implement this in your game's physics. Normally your friction might just slow your player down to zero speed when you're not trying to walk. Instead you can check the ground collider on impact to see if it has a moving platform script, and get the speed of the platform. Then use this speed as the "zero point" for your motion calculation.
I thought this was going to be difficult, but I actually found it really simple to make a solution that seems to work pretty well.
The character in my game has a Box Collider. It's not a trigger and it doesn't use a physics material. It has a Rigidbody with a Mass of 1, Drag of 0, Angular Drag of 0.05, Uses Gravity, is not Kinematic, does not Interpolate, and Collision Detection is Discrete. It has No Constraints. For lateral movement, I use transform.Translate and for jumping I use Rigidbody's AddForce with ForceMode.VelocityChange as the final argument.
The moving platform also has a Box Collider. I set the transform.position based on the results of a call to Vector3.Lerp on every frame. I also have this script on the moving platform:
void OnCollisionEnter(Collision collision) {
// Attach the object to this platform, but have them stay where they are in world space.
collision.transform.SetParent(transform, true);
Debug.Log("On platform.");
}
void OnCollisionExit(Collision collision) {
// Detach the object from this platform, but have them stay where they are in world space.
collision.transform.SetParent(transform.parent, true);
Debug.Log("Off platform.");
}
And that's all. Really, it's just two lines of code in the script to declare that I'm implementing the two methods, and then the actual implementation of each is a single line. All of the info at the start is just for in case the Collision Detection isn't actually working out in your project (I always forget what the rules are for what does and doesn't count as a collision and/or a trigger.)