I have a player character in a topdown game that moves in grid-like movements (1 unit at a time), but when it hits a patch of ice (square), I want it to switch to lerp-movement, slide to the edge, and stop.
Currently I have 5 different colliders as children for each patch of ice: the ice collider itself, and 4 slightly distanced colliders, one for each side of the ice. When it hits the ice collider, depending on which direction it was heading in, it should lerp to the distanced collider associated.
Like so (it's hard to see the main collider but it's there):
Here is the code I have been using for the down key (its basically the same for all keys):
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
Vector2 movementDown = new Vector2(0, -1);
RaycastHit2D hitDown = Physics2D.Raycast(transform.position, movementDown, 0.05f);
if (hitDown.collider && hitDown.collider.gameObject.tag == "barrier")
{
Debug.Log("N/A");
}
else if (onIce)
{
player.transform.position = Vector3.Lerp(transform.position, downIce.transform.position, 100 * Time.fixedDeltaTime);
}
else
{
player.transform.position += new Vector3(movementDown.x, movementDown.y, -0.1f);
}
}
EDIT: code that updates bool 'onIce':
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "ice") {
onIce = true;
}
}
void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.tag == "ice")
{
onIce = false;
}
}
Lerp is only getting called once, when you push the button. One way to fix it is by using a coroutine:
IEnumerator Slide() {
var t = 0f;
var start = player.transform.position; //we will change the position every frame
//so for lerp to work, we need to save it here.
var end = downIce.transform.position;
while(t < 1f){
t += Time.deltaTime;
player.transform.position = Vector3.Lerp(start, end , t);
yield return null; //returning null waits until the next frame
}
}
And then you use it like this:
...
else if (onIce)
{
this.StartCoroutine(this.Slide());
}
else
...
I think this is still not exactly what you want in your game because it will lerp to the center of the collider. If that's the case you can easily fix it by changing how it calculates the end variable in the coroutine to make the player only slide along the correct axis.
Related
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.
I have a platformer game in unity 2D where my I'm trying to make my character have a slight hangtime delay falling down whenever players reached the edge of a platform they will have a small amount of time to jump. However if jump button is press twice quickly the character makes a double jump, character only needs to jump once if not falling on the edge of the platform.
Screenshot scene
Here is what I have done so far for my jumping mechanics:
float Hangtime;
float HangCounter = .3f;
void Update () {
JumpRequest();
}
void FixedUpdate() {
HangtimeImplents();
Jump();
isGrounded = Physics2D.OverlapCircle(feet.position, groundradius, groundlayers);
}
// For Jump --------------
void HangtimeImplents() {
if (isGrounded) // checks if grounded is true then hangtime is always .3f
{
Hangtime = HangCounter;
}
else
{
Hangtime -= Time.deltaTime;
}
}
public void JumpRequest() {
if (CrossPlatformInputManager.GetButtonDown("Jump") && Hangtime > 0f) // checks if Jump Button is pressed and Hangtime is greated than 0
{
isGrounded = false;
Jumprequest = true;
}
}
void Jump() // Jump Function if Jumprequest is true
{
if (Jumprequest)
{
mybody.AddForce(new Vector2(0, jumpforce) , ForceMode2D.Impulse);
}
Jumprequest = false;
}
There are many solutions, but the easiest ways is updating the code like this:
if (CrossPlatformInputManager.GetButtonDown("Jump") && Hangtime == HangCounter) // checks if Jump Button is pressed and Hangtime is greated than 0
{
isGrounded = false;
Jumprequest = true;
}
On your code, Time.deltaTime is less than the frame completion time.
So even isGrounded is false, Hangtime is still greater than 0.
Make an operator called jumpTimes
public int maximizeJumpTimes;
private int jumpTimes
When the player jump, Minus the jumpTimes; and if the jumpTimes == 0 make the player can't jump.
Hope this help :>
My gameobjects are moving oddly.
On the enemy, I have this script :
public float speed = 1.0f;
private Transform target;
public void Start()
{
var player = GameObject.FindWithTag("Player");
target = player.transform;
}
void Update()
{
// Move our position a step closer to the target.
float step = speed * Time.deltaTime; // calculate distance to move
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
// Check if the position of the cube and sphere are approximately equal.
if (Vector3.Distance(transform.position, target.position) < 0.001f)
{
// Swap the position of the cylinder.
target.position *= -1.0f;
}
}
After I hit the enemy with a projectile, it starts moving slower. The script behind the projectile is this :
if (coll.gameObject.tag != "Player")
{
Destroy(gameObject);
if ((coll.collider.GetComponent("Damageable") as Damageable) != null)
{
var d = coll.collider.GetComponent<Damageable>();
d.Damage(1);
}
}
I added this script in, as a Damageable component, however, this behavior was there even before this script was active, so I don't think it's related :
public void Damage(int damageAmount)
{
print("Damage : " + Health + ":" + damageAmount);
Health -= damageAmount;
if (Health <= 0)
{
Destroy(gameObject);
}
}
Any recommendations on what is wrong?
coll
I guess this is short for collision, collision happens on 2 rigidbodies (or another static collider, but unrelated to the question), so when the bullet hit the enemy, it also block the enemy's path, even if you destroy it immediately the enemy will still stop moving for 1 frame.
So make the collider on the bullet to be a trigger, a trigger won't block other rigidbodies.
Use OnTriggerEnter2D (or OnTriggerEnter(Collider) for 3D game) to receive touch event.
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag != "Player")
{
Destroy(gameObject);
var d = other.GetComponent<Damageable>();
if(d != null)
d.Damage(1);
}
}
How can I stop the object from running after spawning to checkpoint?
function OnTriggerEnter(col : Collider)
{
if(col.tag =="Player")
{
SpawnPoint.position = Vector3(transform.position.x, transform.position.y, transform.position.z);
}
}
I found this over at answers.unity3d.com
What you should do is briefly set the rigidbody to kinematic, as well as brakeTorque for all wheel colliders to Mathf.Infinity and than next update switch it back off and the physics engine should reset any forces causing it to move.
Example from link:
function FixedUpdate()
{
// (if the vehicle has been respanwed this frame,
// then a variable respawned is set to true)
if (respawned)
{
wheelCol.brakeTorque = Mathf.Infinity; // Repeat for all wheelcolliders
rigidbody.isKinematic = true;
respawned = false;
}
else
{
rigidbody.isKinematic = false;
// (do the torque calculations here as usual)
}
}
I have used box colliders and GUI function... but the problem with box collider is that your car stops after hitting the collider and and I also want message which is displayed on the sceen to be fade away after 10 seconds.
Here's my code:
var msg = false;
function OnCollisionEnter(theCollision : Collision)
{
if(theCollision.gameObject.name == "trafficLight")
{
Debug.Log("collided");
msg=true;
}
}
function OnGUI ()
{
if (msg== true)
{
GUI.Box (Rect (100,0,500,50), "You need to stop if the traffic signal is red");
}
}
but the problem with box collider is that your car stops after
hitting the collider
You should clarify this. Eventually post another question with the specific problem and possibly an SSCCE.
I also want message which is displayed on the sceen to be fade away
after 10 seconds.
Then put something like this inside the Update method of your MonoBehavior:
float timeElapsed;
float timeLimit = 10f;
void Update()
{
if (msg)
{
timeElapsed += Time.deltaTime;
if (timeElapsed >= timeLimit)
{
msg = false;
timeElapsed = 0f;
}
}
}
Alternative, for a more elegant approach, you can use coroutines:
IEnumerator FadeAfterTime(float timeLimit)
{
yield return new WaitForSeconds(timeLimit);
msg = false;
}
void OnCollisionEnter(Collision collision)
{
if(theCollision.gameObject.name == "trafficLight")
{
msg=true;
StartCoroutine(FadeAfterTime(10f));
}
}
From what I understand, you want a stop message to appear on the screen when the player is near a stop sign, so that the player has to stop the car himself.
In order to do this, for starters you'll need to make your box a trigger instead of a collider. There's a small tickbox on the collider of each object which says Trigger. You'll want this to be ticked.
Then put a script similar to this in the trigger box near your traffic light:
var msg = false;
function Start()
{
}
function OnTriggerEnter(theCollision : Collision)
{
if(theCollision.gameObject.name == "car") //where "car" you put the name of the car object
{
msg = true;
StartCoroutine(FadeAfterTime(10f));
}
}
IEnumerator FadeAfterTime(float timeLimit)
{
yield return new WaitForSeconds(timeLimit);
msg = false;
}
function OnGUI ()
{
if (msg== true)
{
GUI.Box (Rect (100,0,500,50), "You need to stop if the traffic signal is red");
}
}
function Update()
{
}
In essence the traffic light trigger box will detect when the car enters the designated area, and will display the GUI, with the fade out script provided by Heisenbug in the previous answer.
I can't test this myself at the moment, but it should work for you. If you have any questions, lemme know.
You should use RayCasting function for this purpose.
I have provided a real example here.
using UnityEngine;
using System.Collections;
public class carMovement : MonoBehaviour {
bool isStop = false;
public float speed = 30f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (!isStop) {
transform.position += (Vector3.forward * Time.deltaTime * speed);
var fwd = transform.TransformDirection (Vector3.forward);
Debug.DrawRay (transform.position, fwd, Color.green);
if (Physics.Raycast (transform.position, fwd, 10)) {
print ("There is something in front of the object!");
isStop = true;
transform.position = transform.position;
}
}
}
}