I need to make a platform that moves up when the player enters it.
MovingPlatform.cs
public class MovingPlatform : MonoBehaviour
{
[SerializeField]
private Vector3 newPosition;
void Start()
{
newPosition = new Vector3(transform.position.x, transform.position.y + 5, transform.position.z);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
transform.position = Vector3.MoveTowards(transform.position, newPosition, 4 * Time.deltaTime);
}
}
}
My problem is that the platform moves up only a little and without the player.
Why the platform moves only once
The reason, the platform moves only once is due to OnTriggerEnter getting called upon entering the trigger not staying inside it. If you want it to get called constantly, while inside it, use OnTriggerStay instead or assign a boolean value inside OnTriggerEnter and OnTriggerExit methods and change your position inside an Update/FixedUpdate.
Why the platform moves without the player
Regarding the platform moving without the player, I'm assuming that the player is a physics object and you expect them to be pushed by it. Potential reasons for that happening:
You are moving the platform too fast
You are moving the platform outside the physics loop
The platform and/or player doesn't have a collider (Trigger colliders do not collide)
Potential solution
It uses OnCollisionEnter instead of the OnTriggerEnter since it seemed to be more appropriate in this case (Make sure to have a non-trigger collider, if you gonna use it).
using UnityEngine;
public class MovingPlatform : MonoBehaviour
{
[SerializeField]
private Vector3 targetPosition = default;
private bool touchingPlayer = false;
private void Start()
{
targetPosition = new Vector3(
transform.position.x,
transform.position.y + 5f,
transform.position.z);
}
private void FixedUpdate()
{
if (touchingPlayer)
{
transform.position = Vector3.MoveTowards(
transform.position,
targetPosition,
4f * Time.fixedDeltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Player"))
touchingPlayer = true;
}
private void OnCollisionExit(Collision collision)
{
if (collision.gameObject.CompareTag("Player"))
touchingPlayer = false;
}
}
https://streamable.com/mbevlw
Instead Of Moving the platform using Vector3s, Create an animation that plays when the player enters a trigger zone.
Related
Hey I just want my bullet to destroy itself when it touch Ground i tried to destroy after 2 seconds but it has the same problem That's My Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyBullet : MonoBehaviour
{
GameObject target;
public float speed;
Rigidbody2D bulletRB;
void Start()
{
bulletRB = GetComponent<Rigidbody2D>();
target = GameObject.FindGameObjectWithTag("Player");
Vector2 moveDir = (target.transform.position - transform.position).normalized * speed;
bulletRB.velocity = new Vector2(moveDir.x, moveDir.y);
Destroy(this.gameObject, 2);
}
}
Destroy the bullet object using the Destroy method.The bullet is destroyed after flying a certain distance.
public float speed;
public float destoryDistance;
private Rigidbody2D rg2d;
private Vector3 startPos;
// Start is called before the first frame update
void Start()
{
rg2d = GetComponent<Rigidbody2D>();
rg2d.velocity = transform.right * speed;
startPos = transform.position;
}
// Update is called once per frame
void Update()
{
float distance = (transform.position - startPos).sqrMagnitude;
if (distance > destoryDistance)
{
Destroy(gameObject);
}
}
Use OnCollisionEnter() to destroy to bullet
void OnCollisionEnter(Collision collider)
{
if (collider.GameObject.tag == "Ground")
{
Destroy (this.GameObject)
}
}
What's happening here is that this function gets called every time it collides with an object, so we put the destroy code here. It takes the collider as a parameter, and then checks if the GameObject has the tag "Ground", and if it does, destroy itself.
Note that you will also have to add a tag to your ground objects in the hiearchy. You can name them anything else too, but make sure to change "Ground" in the code when you do set the tag to anything other than it.
You will probably also have other colliders like walls in your game so you should make a universal tag that destroys bullets and name it something like "Destroy Projectiles" or something.
Edit: You can have multiple functions that destroy the GameObject.
Sorry for the bad formatting I don't know how to do this. I'm using 2020.3.21f1 and following a tutorial and when the enemy circle hits the player he doesn't take damage. when they collide they don't overlap at all, but the Debug.log isn't registering either so I think that the circle collider 2D is the problem. the enemy sprite still moves towards the player when it is in range. another problem (that will turn into a feature if I cant figure out how to change it) is that when the enemy collides with the player and the player pushes it goes the direction it was pushed until it runs into something Here's the tutorial I'm following
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy: MonoBehaviour
{
public float speed = 3f;
private Transform target;
[SerializeField] private float attackDamage = -10f;
private void Update(){
if (target != null){
float step = speed*Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, target.position, step);
}
}
private void OnCollision(Collision2D other){
if (other.gameObject.tag == "player"){
Debug.Log("hit");
other.gameObject.GetComponent<PlayerHealth>().UpdateHealth(attackDamage);
}
}
private void OnTriggerEnter2D(Collider2D other) {
if(other.gameObject.tag == "Player"){
target = other.transform;
Debug.Log(target);
}
}
private void OnTriggerExit2D(Collider2D other) {
if(other.gameObject.tag == "Player"){
target = null;
Debug.Log(target);
}
}
}
The sprite by itself wont detect collision, you need to add a box collider for that. If you add that component to the player then modify your code to include those collision detections then it should function ad intended.:)
-TheHackintoshProgrammer;
Or making them bounce when colliding. but now it's not detecting any collision.
The first cube have a Rigidbody Use Gravity and Is Kinematic both checked enabled true.
If I will disable the Is Kinematic the cube will fall down.
Both cubes have attached the same script.
Both cubes have a box collider and the Is Trigger on both is unchecked disabled.
This script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Door : MonoBehaviour
{
public Transform target;
public float speed;
private void Start()
{
}
private void Update()
{
float step = speed * Time.deltaTime; // calculate distance to move
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
}
}
Each cube have the script and target is the other cube. So both cubes are moving to each other but never collide.
Both cubes settings screenshot :
It would be better practice set rigidbody.velocity once instead of changing transform.position every frame, but this solution should work regardless:
private bool collided = false;
private void Move() {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
}
private void Update() {
if (!collided) {
Move();
}
}
private void OnCollisionEnter(Collider other) {
if (other.gameObject.GetComponent<Door>() != null) {
collided = true;
}
}
This may not be the best way to do it depending on how you plan on moving forward, but this is a way that works.
If you want to make them bounce, I'd suggest using rigidbody.AddForce() or set rigidbody.velocity. Then you can either use a bouncy physic material or changing the OnCollisionEnter code to use rigidbody.AddForce() or rigidbody.velocity when they collide with each other.
I am trying to make a 2.5D SHMUP type game in which the world continuously moves forward while the player's spaceship and camera stay in place. This means that even if the world is moving, if the player's ship is in the middle of the screen it will stay there.
To do this I've created an empty game object named Moving World and attached the following script to it:
public class movingWorldController : MonoBehaviour
{
private float movementSpeed = 5f;
void Update()
{
transform.position = transform.position + new Vector3(0, 0, movementSpeed * Time.deltaTime);
}
}
I then added the camera and spaceship as children to of this object, and as a result they indeed move with the moving world object. However, I also have a script attached to the spaceship to allows it to move according to the player's input, and if I enable the script above the ship stops responding to the player's input. The ship's script looks like this:
public class ShipController : MonoBehaviour
{
public Rigidbody rb;
public float moveSpeed = 5f;
private Vector3 movement;
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.z = Input.GetAxisRaw("Vertical");
}
private void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.deltaTime);
}
}
The ship controller works just fine when the world-moving script is disabled, so I suspect the world script is somehow overwriting the spaceship position. How may I solve this?
For a POC example see this video: https://www.youtube.com/watch?v=-fVjWgfUKn4&t=282s (jump to 4:00 to see the game in action). Note that in the video gamemaker is used to achieve the effect, while I am trying to achieve a similar effect using just code.
I achieved the effect I was aiming for by doing the following. First, I removed the MovingWorld object and instead applied the following script to the camera:
public class movingWorldController : MonoBehaviour
{
public float movementSpeed = 5f;
void FixedUpdate()
{
transform.position = transform.position + new Vector3(0, 0, movementSpeed * Time.deltaTime);
}
}
This will cause the camera to continuously move forward. Next, to make sure the player's ship keeps up with the camera, and is maneuverable at the same time, I applied the following script to the ship's object:
public class ShipController : MonoBehaviour
{
public Rigidbody rb;
private float shipVelocity = 5f;
public float moveSpeed = 10f;
private Vector3 movement;
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal") * moveSpeed;
movement.z = Input.GetAxisRaw("Vertical") * moveSpeed + shipVelocity;
}
private void FixedUpdate()
{
rb.MovePosition(rb.position + movement * Time.deltaTime);
}
}
Two important notes:
The shipVelocity variable was introduced to make sure the ship continues to cruise at camera-speed.
Even though the camera is not a RigidBody its position update must occur during the FixedUpdate method to make sure it moves on the same frame as the ship. Updating it using the Update method will introduce jittering to the ship due to de-synchronization.
I'm working on my very first Unity game. It's still in prototype and will be very simple anyways, consisting of a cube as the player and spheres as enemies.
I'm trying to write a code with AddForce to knock the player a pretty good distance in an arc in the direction opposite of the enemy when they come in contact, but I still have a primitive understanding of how to use AddForce and can't seem to get force applied in any direction at all. The player just moves through the enemy.
Here's the only thing I could manage to scrap together and it is obviously insufficient:
if (other.gameObject.tag == "Enemy")
{
playerDead = true;
Rigidbody rigidbody = other.GetComponent<Rigidbody> ();
rigidbody.AddForce (transform.forward * 100);
}
I can post a screenshot if it helps.
Instead of transform.forward, use a more tailored direction depending on the position of both units
public float speed = 100;
if (other.gameObject.tag == "Enemy")
{
playerDead = true;
Vector3 direction = (transform.position - other.transform.position).normalized;
other.GetComponent<Rigidbody>().AddForce (direction * speed);
}
Edit: You must make sure that the rigidbody is on the game object calling the OnCollisionEnter function, it cant just be on any of the objects involved in the collision.
I cannot comment so I must make an answer.
You have an isTrigger set up apparenty. Be sure to turn isTrigger OFF or your player will walk through the enemy collider.
[SerializeField]
private float speed = 100;
private bool playerDead;
OnCollisionEnter(Collision collision)
{
if(collision.gameObject.tag == "Enemy")
{
playerDead = true;
Vector3 direction = (transform.position - collision.transform.position).normalized;
collision.GetComponent<Rigidbody>().AddForce (direction * speed,0,0);
//AddForce is a vector3 apparently and requires (x,y,z)
// Also note that I'm getting errors with the "collision.GetComponent<>"
// You're going to want to remove "collision"
// I think the smarter approach maybe to declare a public Rigidbody variable ( Up Top )
[SerializeField]
private Rigidbody playerRidg;
playerRidg = GetComponent<Rigidbody>().AddForce(direction * speed,0,0);
}
}
My solution using coroutine which toggles a bool "spikes":
Player collision:
private void OnTriggerEnter2D(Collider2D collision){
if (collision.gameObject.tag == "Spike" )
{
StartCoroutine(Knockback());
}
}
Coroutine:
IEnumerator Knockback()
{
spikes = true;
yield return new WaitForSecondsRealtime(0.3f);
spikes = false;
}
Whenever the spikes bool is true player will be moved
void FixedUpdate()
{
if (spikes ==true)
{
Vector2 NewPosition = new Vector2(10.0f, 10.0f);
moveCharacter(NewPosition);
}
}