Unity2D inconsistent AddForce - unity3d

I just recently asked another question and I got answered really quick so I hope its the same with this one. Anyway, I'm making this 2D platformer (super-meat-boy like) and I've added in this cool 'Dash' ability which is triggered when you press Shift. It would add an x-axis force and a little bit of some y-axis force to give it more of a jump-like feel. However, the AddForce function is so inconsistent in the game. Sometimes, the y-axis force is larger than the x-axis and sometimes the x-axis is increased by half(??). The only reason I can think of why this happens is because I have increased the gravity for proper unrealistic but good looking jumping and slightly more increased when the player dashes. Or could it be that when I dash at the peak of my jump, there's a stronger force as compared to in the beginning of the dash? I'm so confused.
Here is everything that in the update() function.
void Update()
{
//Flipping and moving lightfeet
if (Input.GetKey(KeyCode.A))
{
anim.SetFloat("Horizontal", 1);
x = -1;
scale.x = -4;
rb.velocity = new Vector2(-speed, rb.velocity.y);
}
else if (Input.GetKey(KeyCode.D))
{
anim.SetFloat("Horizontal", 1);
x = 1;
scale.x = 4;
rb.velocity = new Vector2(speed, rb.velocity.y);
}
else //no keys pressed
{
anim.SetFloat("Horizontal", 0);
rb.velocity = new Vector2(0f, rb.velocity.y);
anim.SetBool("Sprint", false); //even after sprinting and then stopping before to jump, sprint anim wont play
}
transform.localScale = scale;
//Accumulating jump charge and increasing speed!
if (Input.GetKey(KeyCode.Space) && rb.velocity.y == 0f) //only if space is held down and there is no vertical movement
{
jumpAccumulator += Time.deltaTime * 25f; //accumulates jump power over time
if (jumpAccumulator >= maxJumpAccumulator) //maximum jump power
{
jumpAccumulator = maxJumpAccumulator;
}
speed *= sprintSpeed; //increase speed when charging up
if(speed >= maxSpeed) //maximum speed
{
speed = maxSpeed;
}
}
//Ground detection
groundHit = Physics2D.BoxCast(bcollider.bounds.center, bcollider.bounds.size, 0f, Vector2.down, 0.1f ,groundmask);
mapHit = Physics2D.BoxCast(bcollider.bounds.center, bcollider.bounds.size, 0f, Vector2.down, 0.1f, mapMask);
if (groundHit.collider != null || mapHit.collider != null) //When you on the ground!
{
anim.SetBool("Jumped", false);
anim.SetBool("DoubleJumped", false);
anim.SetBool("Dashed", false);
anim.SetBool("Fall", false);
canJump = true;
canDoubleJump = true;
canDash = false;
rb.gravityScale = 15; //nomral gravity scale
//animations for running or sprinting
if (speed <= initialspeed)
{
anim.SetBool("Sprint", false);
}
else if (speed > initialspeed && rb.velocity.x > initialspeed && rb.velocity.y == 0 || speed > initialspeed && rb.velocity.x < -initialspeed)
{
anim.SetBool("Sprint", true);
}
}
else if (groundHit.collider == null || mapHit.collider == null) //if LF is not on ground!
{
canJump = false;
anim.SetFloat("Horizontal", 0f);
}
//falling without jumping
if (rb.velocity.y < 0 && anim.GetBool("Jumped") == false && anim.GetBool("DoubleJumped") == false && anim.GetBool("Dashed") == false)
{
anim.SetBool("Fall", true);
anim.SetBool("Sprint", false);
canDash = true;
}
JumpDash();
}
void JumpDash()
{
//Jump
if (Input.GetKeyUp(KeyCode.Space) && canJump == true)
{
rb.velocity = Vector2.up * (jumpForce + jumpAccumulator);
anim.SetBool("Jumped", true);
anim.SetBool("DoubleJumped", false); //setting false to prevent bugs
anim.SetBool("Sprint", false); //setting false to sprint here as well just to prevent bugs
canDash = true;
jumpAccumulator = 1;
}
//Double Jump
if(Input.GetKeyDown(KeyCode.W) && canJump == false && canDoubleJump == true)
{
rb.velocity = Vector2.up * jumpForce;
canDoubleJump = false;
anim.SetBool("Jumped", false);
anim.SetBool("DoubleJumped", true);
anim.SetBool("Dashed", false); //disabling dash animation so it doesn't play when dashing then double jumping (because conditions for both can be true at the same time)
anim.SetBool("Sprint", false); //setting false to sprint here as well just to prevent bugs
anim.SetBool("Fall", false);
doubleJumpFX.Play();
DashFX.Stop();
}
//Dash
if(Input.GetKeyDown(KeyCode.LeftShift) && canDash == true)
{
rb.AddForce(new Vector2(dashForce * x, dashUpForce), ForceMode2D.Impulse);
rb.gravityScale += dashGravity; //increasing gravity for dashing
canDash = false;
anim.SetBool("Jumped", false);
anim.SetBool("DoubleJumped", false);
anim.SetBool("Dashed", true);
anim.SetBool("Sprint", false); //setting false to sprint here as well just to prevent bugs
doubleJumpFX.Stop();
DashFX.Play();
}
}
void OnCollisionEnter2D(Collision2D collision)
{
Debug.Log("Collider: " + collision.collider.name);
if (collision.collider.name == "platform" || collision.collider.name == "mapColliders")
{
speed = initialspeed; //set speed to normal on hitting the ground (difference between this and raycast is this returns true for only one frame)
anim.SetBool("Dashed", false); //setting false to this anim here again to prevent buggy animations
anim.SetBool("Fall", false);
doubleJumpFX.Stop();
DashFX.Stop();
}
if (collision.collider.name == "Respawn area")
{
transform.position = new Vector2(-13f, 4f);
}
}

The inconstancy of AddForce is because you are adding onto the player's existing force. Have you tried cancelling out existing forces before calling AddForce? Just add the following line
rb.velocity = new Vector2 (0, 0);
in front of the AddForce function. Your dash function should look like this
//Dash
if(Input.GetKeyDown(KeyCode.LeftShift) && canDash == true)
{
rb.velocity = new Vector2 (0, 0);
rb.AddForce(new Vector2(dashForce * x, dashUpForce), ForceMode2D.Impulse);
rb.gravityScale += dashGravity; //increasing gravity for dashing
canDash = false;
anim.SetBool("Jumped", false);
anim.SetBool("DoubleJumped", false);
anim.SetBool("Dashed", true);
anim.SetBool("Sprint", false); //setting false to sprint here as well just to prevent bugs
doubleJumpFX.Stop();
DashFX.Play();
}

Related

Unity Mobile - How to make fluid swipe to move movement?

So I am working on a personal project, and I had this idea for a movement that I don't know to realize. So the project(game) is for phone, and what I want to, is to when I swap in a direction, that vector becomes its closest axis (ex: 70 degrees will be (0,1) while 35 will be (1,0)). So when I get a swipe, I want my character to move in that direction. MAIN ISSUE is I don't know how to make him dash to that location. I know how to make him TELEPORT, but not how to make him DASH. I tried going for Vector2.Lerp, but it is a bit buggy and feels like character does not react on time. Here is the script:
private void Update()
{
if (gameObject.GetComponent<OnDeath>().isDead == false)
{
if (trigger)
{
fractionOfWayThere += 0.1f;
transform.position=Vector2.Lerp(transform.position, finish, fractionOfWayThere);
isMoving = true;
}
if ((Vector2)transform.position == finish)
{
isMoving = false;
animator.SetBool("isMoving", false);
}
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
startPos = cam.ScreenToWorldPoint(touch.position);
}
if (touch.phase == TouchPhase.Ended)
{
endPos = cam.ScreenToWorldPoint(touch.position);
destination = endPos - startPos;
if (Mathf.Abs(destination.x) > Mathf.Abs(destination.y))
{
destination = new Vector2(Funkcija(destination.x), 0);
}
if (Mathf.Abs(destination.x) < Mathf.Abs(destination.y))
{
destination = new Vector2(0, Funkcija(destination.y));
}
if (Mathf.Abs(destination.x) == Mathf.Abs(destination.y))
{
destination = new Vector2(Funkcija(destination.x), 0);
}
finish = (Vector2)transform.position + destination.normalized;
if (Physics2D.OverlapCircle(finish, 0.1f, spike) != null)
{
if (finish.x < transform.position.x)
{
sr.flipX = true;
}
else if (finish.x > transform.position.x)
sr.flipX = false;
trigger = true;
fractionOfWayThere = 0;
isMoving = true;
animator.SetBool("isMoving", true);
}
else
{
finish = transform.position;
}
}
}
}
}
Most of the code is getting the swipe into its axis and flipping sprite, only thing regarding the movement is this:
if (trigger)
{
fractionOfWayThere += 0.1f;
transform.position=Vector2.Lerp(transform.position, finish, fractionOfWayThere);
isMoving = true;
}
Playtesting, this feels realy weird. I tried Vector2.MovePosition(), rb.AddForce() and rb.MovePosition. Any other way to do this, or even using those functionts I have not thought of? All feedback would be highly appreciated!
Lerp is a good Start, but it's linear. A Dash would typically start instantly and slow down over time.
to achieve framerate independent movement, you should use Time.deltaTime in Update. It's neglectable in FixedUpdate as these occur at (almost) fixed timesteps.
You can achieve that by adding an AnimationCurve to your code:
[...]
public AnimationCurve dashCurve = new AnimationCurve.Linear(0,0,1,1); // modify this in inspector!
[...]
if (trigger)
{
fractionOfWayThere += 0.5f * Time.deltaTime; // fractionOfWayThere takes 0.5 second to grow from 0 to 1.
transform.position = Vector2.Lerp(transform.position, finish, dashCurve.Evaluate(fractionOfWayThere));
isMoving = true;
}
Set up the AnimationCurve like this:

Unity 2D Platformer - making my enemy not see through walls

basicly i'm searching for an idea. How to make my Enemy patroling, but when it reaches the Player - it rush and deal damage, but in the same time when it reach the wall and player is standing behind the wall it Don't attack. You know - i don't want to let them see through walls.
I have made simple Game Object (rectangle) to point it's sight, it is working correctly but i want to improve some of it.
To make it quckier... i just want to make my enemies attack me but to not seen me througth walls
Some code:
[DamageFromEnemy.cs]
private void FixedUpdate()
{
isThatPlayer = Physics2D.OverlapBox(PlayerDetector.position, new Vector2(playerDetectX, playerDetectY), 0, PlayerLayer);
isThatWall = Physics2D.OverlapBox(PlayerDetector.position, new Vector2(playerDetectX, playerDetectY), 0, gameObject.GetComponent<EnemyScript>().WallLayer);
if (isThatWall == true && gameObject.GetComponent<EnemyScript>().movingRight == true)
{
PlayerDetector.transform.Translate(new Vector3(changePosX, 0, 0));
//playerDetectX -= PlayerDetector.transform.position.x; // Lowering size. Not Working
changePosX = (playerDetectX / 2) * (1 / enemyScaleX) + (enemyScaleX / 2) * (1 / enemyScaleX);
Debug.Log("pozycja x: " + changePosX);
}
if (isThatWall == true && gameObject.GetComponent<EnemyScript>().movingRight == false)
{
PlayerDetector.transform.Translate(new Vector3(- changePosX, 0, 0));
//playerDetectX -= PlayerDetector.transform.position.x; // Lowering size. Not Working
changePosX = (playerDetectX / 2) * (1 / enemyScaleX) + (enemyScaleX / 2) * (1 / enemyScaleX);
Debug.Log("pozycja x: " + changePosX);
}
DetectPlayer();
AttackTimer();
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireCube(PlayerDetector.position, new Vector3(playerDetectX, playerDetectY));
}
[EnemyScript.cs]
void Update ()
{
trap = Physics2D.OverlapCircle(ColideDetector.position, detectorRadius, TrapLayer);
otherEnemy = Physics2D.OverlapCircle(ColideDetector.position, detectorRadius, EnemyLayer);
if (health <= 0)
{
Destroy(gameObject);
}
transform.Translate(Vector2.right * speed * Time.deltaTime );
RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, distance);
RaycastHit2D wallInfoR = Physics2D.Raycast(wallDetection.position, Vector2.right, distance, WallLayer);
RaycastHit2D wallInfoL = Physics2D.Raycast(wallDetection.position, Vector2.left, -distance, WallLayer);
if (groundInfo.collider == false || trap == true || otherEnemy == true || wallInfoR == true || wallInfoL == true)
{
if(movingRight == true)
{
transform.eulerAngles = new Vector3(0, -180, 0);
movingRight = false;
}
else
{
transform.eulerAngles = new Vector3(0, 0, 0);
movingRight = true;
}
}
}
Some Gif Feedback
At last gifs frames you can see that it bugs sometimes.
public PlayerControls player;
public LayerMask WallLayer;
player = FindObjectOfType<PlayerControls>();
RaycastHit2D checkWallsToHero = Physics2D.Raycast(wallToHeroRay.position, player.transform.position, 150,WallLayer);
if (checkWallsToHero == true)
{
playerCheck = false;
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireCube(PlayerDetector.position, new Vector3(playerDetectX, playerDetectY));
Gizmos.DrawLine(wallToHeroRay.position, player.transform.position);
}
[New Code sample - propably wrong]:
isThatPlayer = Physics2D.OverlapBox(PlayerDetector.position, new Vector2(playerDetectX, playerDetectY), 0, PlayerLayer);
isThatWall = Physics2D.OverlapBox(PlayerDetector.position, new Vector2(playerDetectX, playerDetectY), 0, gameObject.GetComponent<EnemyScript>().WallLayer);
RaycastHit2D checkWallsToHero = Physics2D.Raycast(wallToHeroRay.position, player.transform.position, 0, gameObject.GetComponent<EnemyScript>().WallLayer);
if (checkWallsToHero.collider != true /*&& isThatPlayer == true*/)
{
Debug.Log("Pierwszy state");
Debug.Log(checkWallsToHero.collider);
//Debug.Log(isThatPlayer);
//Debug.Log("Hit: " + checkWallsToHero.collider.gameObject.name);
playerCheck = false;
enemyAttackReady = false;
coolDownTimer = 0;
enemyAttackCD = 0;
}
else if (checkWallsToHero.collider == true && isThatPlayer == true)
{
Debug.Log(checkWallsToHero.collider);
Debug.Log("Drugi state");
ReadyToAttack(); //charging enemy
DetectPlayer(); //bool to true when OverlapBox hits player
AttackTimer(); //cd between enemy attacks
}
if (Physics2D.Raycast2D
(wallToHeroRay.position,player.transform.position,out hit,10)
&&hit.transform.gameObject.tag == "Player")
{
RayHit = true;
}
else {
RayHit = false;
}
to use this you will have to tag your player as 'Player' then your ray will only give you a hit if it hits the player itself, and not a wall
Edit: this is code i threw together following #Draco18s's idea in the comments, if it works for you, tell him thank you. i just thought it made enough sense he should have put it as an answer

Making a volleyball game, overlap not working

I'm making a 2D game on Unity and I created an overlap to see if the ball is on the hit area. However, whenever I push the hit button, the ball is hit even if it is away of the player. I am sending the code for the Player, which contains what is needed so far, to see what may have gone wrong. Supposedly with the foreach hitCollider in hitColliders it should be fixed but it is not working I and just canĀ“t wrap my mind around it.
public int speed;
public bool estoyFloor, subiendo, bajando;
public bool canRight, canLeft;
public bool canMove;
public float posYinit;
public Vector3 posInitPlayer;
bool m_Started;
public LayerMask m_LayerMask;
public GameObject volleyBall;
// Use this for initialization
void Start () {
m_Started = true;
}
void FixedUpdate()
{
Collider2D[] hitColliders = Physics2D.OverlapBoxAll(gameObject.transform.position, transform.localScale / 2, 0);
foreach (Collider2D hitCollider in hitColliders)
{
if (Input.GetButtonDown("Fire1"))
{
volleyBall.GetComponent<Rigidbody2D>().velocity = Vector3.zero;
volleyBall.GetComponent<Rigidbody2D>().AddForce(new Vector3(300, 500));
}
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
if (m_Started)
Gizmos.DrawWireCube(transform.position, transform.localScale / 2);
}
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1"))
canMove = true;
if (Input.GetAxisRaw("Horizontal") > 0 && canRight)
transform.position += Vector3.right * speed * Time.deltaTime;
if (Input.GetAxisRaw("Horizontal") < 0 && canLeft)
transform.position += Vector3.left * speed * Time.deltaTime;
if (Input.GetButtonDown("Jump") && estoyFloor)
{
subiendo = true;
posYinit = transform.position.y;
}
if (transform.position.y > posYinit + 2.5f)
{
subiendo = false;
bajando = true;
}
if (!estoyFloor && !subiendo)
bajando = true;
Debug.DrawLine(transform.position, transform.position + new Vector3(0, -1, 0), Color.red);
Debug.DrawLine(transform.position, transform.position + new Vector3(0.8f, 0, 0), Color.red);
Debug.DrawLine(transform.position, transform.position + new Vector3(1.5f, 0, 0), Color.red);
RaycastHit2D[] hitDown = Physics2D.LinecastAll(transform.position, transform.position + new Vector3(0, -1, 0));
RaycastHit2D[] hitsRight = Physics2D.LinecastAll(transform.position, transform.position + new Vector3(0.8f, 0, 0));
RaycastHit2D[] hitsLeft = Physics2D.LinecastAll(transform.position, transform.position + new Vector3(1.5f, 0, 0));
estoyFloor = false;
foreach (RaycastHit2D hit in hitDown)
{
if (hit.collider.name == "Floor")
{
bajando = false;
estoyFloor = true;
}
}
canRight = true;
foreach (RaycastHit2D hit in hitsRight)
{
if (hit.collider.tag == "Wall")
canRight = false;
}
canLeft = true;
foreach (RaycastHit2D hit in hitsLeft)
{
if (hit.collider.tag == "Wall")
canLeft = false;
}
if (subiendo)
transform.position += Vector3.up * speed * Time.deltaTime;
if (bajando)
transform.position += Vector3.down * speed * Time.deltaTime;
}
Your overlap box is probably colliding with the player it is on. Because you do not check if the collider belonged to the volleyball in your loop, you are hitting the ball no matter what. Try to get the transform from the collider and check its tag to see if it is a volleyball before adding force to the ball and see if that works. You could also use a layermask on your Overlap box check as well to ensure only volleyballs get detected.

Unity 3rd person controller, rotation nightmare

I am trying to make a MMO character controller like the one of this Youtube video:https://www.youtube.com/watch?v=fOvf7gRO_aM
Basically, you use WASD to move around.
You can move the camera by mouse click and drag, and when moving, you character will now move in the new camera direction.
The thing is, i would like that when i press WASD, that the character (not the camera) would face the direction of the mouvement.
I tried to use this:
if (Input.GetAxis("Vertical") > 0 | Input.GetAxis("Vertical") < 0){
Quaternion turnAngle = Quaternion.Euler(0, centerPoint.eulerAngles.y, 0);
character.localRotation = Quaternion.Slerp(character.rotation, turnAngle, Time.deltaTime * rotationSpeed);
}
The character was not facing the right direction, so i tried this
if (Input.GetAxis("Vertical") > 0 | Input.GetAxis("Vertical") < 0){
Quaternion turnAngle = Quaternion.Euler(0, centerPoint.eulerAngles.y, 0);
character.rotation = Quaternion.LookRotation(movement);
}
but that does not seem to work. I am a noob after all :D
Here is the full code of the controller's move part:
private void Move()
{
moveFrontBack = Input.GetAxis("Vertical") * moveSpeed;
moveLeftRight = Input.GetAxis("Horizontal") * moveSpeed;
Vector3 movement = new Vector3(moveLeftRight, 0, moveFrontBack);
movement = character.rotation * movement;
characterController.Move(movement * Time.deltaTime);
//Animation on move
if (movement.magnitude != 0)
{
anim.SetBool("isWalking", true);
anim.SetBool("isIdle", false);
}
if (movement.magnitude == 0)
{
anim.SetBool("isWalking", false);
anim.SetBool("isIdle", true);
}
centerPoint.position = new Vector3(character.position.x, character.position.y + mouseYPosition, character.position.z);
//The place where things go south it seems
if (Input.GetAxis("Vertical") > 0 | Input.GetAxis("Vertical") < 0)
{
Quaternion turnAngle = Quaternion.Euler(0, centerPoint.eulerAngles.y, 0);
character.rotation = Quaternion.Slerp(character.rotation, turnAngle, Time.deltaTime * rotationSpeed);
}
I had a previous version on the controller, without the change of camera with mouse, but the right character's behaviour facing the direction of the input:
private void Move()
{
moveFrontBack = Input.GetAxis("Vertical") * moveSpeed;
moveLeftRight = Input.GetAxis("Horizontal") * moveSpeed;
Vector3 movement = new Vector3(moveLeftRight, 0, moveFrontBack);
characterController.Move(movement * Time.deltaTime);
if (movement != Vector3.zero) transform.rotation = Quaternion.LookRotation(movement);
if (movement.magnitude != 0)
{
anim.SetBool("isWalking", true);
anim.SetBool("isIdle", false);
}
if (movement.magnitude == 0)
{
anim.SetBool("isWalking", false);
anim.SetBool("isIdle", true);
}
playerCamera.position = new Vector3(character.position.x, character.position.y + yCamera, character.position.z + zCamera);
}
Also, here is the mousemoving part:
void MouseTurnAround()
{
zoom += Input.GetAxis("Mouse ScrollWheel") * zoomSpeed;
if (zoom > zoomMin)
zoom = zoomMin;
if (zoom < zoomMax)
zoom = zoomMax;
playerCamera.transform.localPosition = new Vector3(0, 0, zoom);
if (Input.GetMouseButton(0))
{
mouseX += Input.GetAxis("Mouse X");
mouseY -= Input.GetAxis("Mouse Y");
}
mouseY = Mathf.Clamp(mouseY, -60f, 60f);
playerCamera.LookAt(centerPoint);
centerPoint.localRotation = Quaternion.Euler(mouseY, mouseX, 0);
}
I don't really have more ideas, so maybe smart people can see what they can do ! Thanks in advance..
I managed some kind of a mix of my 2 solutions, and parented my character to an empty gameobject, which receives the new rotations. Then, i leave the character be oriented to the movement with look rotation.
private void Move()
{
moveFrontBack = Input.GetAxis("Vertical") * moveSpeed;
moveLeftRight = Input.GetAxis("Horizontal") * moveSpeed;
Vector3 movement = new Vector3(moveLeftRight, 0, moveFrontBack);
movement = character.rotation * movement;
characterController.Move(movement * Time.deltaTime);
//Animation on move
if (movement.magnitude != 0)
{
anim.SetBool("isWalking", true);
anim.SetBool("isIdle", false);
}
if (movement.magnitude == 0)
{
anim.SetBool("isWalking", false);
anim.SetBool("isIdle", true);
}
centerPoint.position = new Vector3(character.position.x, character.position.y + mouseYPosition, character.position.z);
//Rotates the character to move towards new direction
if (Input.GetAxis("Vertical") > 0 | Input.GetAxis("Vertical") < 0)
{
Quaternion turnAngle = Quaternion.Euler(0, centerPoint.eulerAngles.y, 0);
character.rotation = Quaternion.Slerp(character.rotation, turnAngle, Time.deltaTime * rotationSpeed);
}
if (movement != Vector3.zero) lkModel.rotation = Quaternion.LookRotation(movement);
}

Character is not colliding with other other objects in Unity3D

I'm working on a game right now (first 3D styled game), and I have a problem with my character colliding. I have a Player object, which has another object(s) as the real moveable characters (now I have only one). I have rigidbody and box collider too attached to my character. I have made a level (with hand-placed platforms), and I would like avoid my character of falling of the platforms, while the user control it. I have tried to place a cube on the side of the platform(s), with box collider attached to it, but the character not detect the colliding for some reasons. I would like my character to be stopped by the collider "cube", but it doesn't happen.
I use this script to move my object (attached to my character Player object) :
public class Bounce : MonoBehaviour {
float lerpTime;
float currentLerpTime;
float perc = 1;
Vector3 startPos;
Vector3 endPos;
bool firstInput;
public bool justJump;
public GameObject player;
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) {
if (perc == 1) {
lerpTime = 1;
currentLerpTime = 0;
firstInput = true;
justJump = true;
}
}
startPos = gameObject.transform.position;
if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));
}
if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) {
endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, -1f));
}
if (firstInput == true) {
currentLerpTime += Time.deltaTime * 5;
perc = currentLerpTime / lerpTime;
gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc);
if (perc > 0.8f) {
perc = 1;
}
if (Mathf.Round(perc) == 1) {
justJump = false;
}
}
}
void OnCollisionEnter(Collision collision) {
Debug.Log("!!!!!!!");
}
}
And I use this script on the character itself: (to rotate and animate it)
Code (csharp):
public class AnimationController : MonoBehaviour {
Animator anim;
public GameObject thePlayer;
// Use this for initialization
void Start () {
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
Bounce bounceScript = thePlayer.GetComponent<Bounce>();
if (bounceScript.justJump == true) {
anim.SetBool("Jump", true);
}
else {
anim.SetBool("Jump", false);
}
if (Input.GetButtonDown("right")) {
//transform.rotation *= Quaternion.Euler(0,30,0);
transform.RotateAround(transform.position, Vector3.up, 90);
}
if (Input.GetButtonDown("left")) {
transform.Rotate (0, -90, 0, 0);
}
}
}
It's only colliding when the cube not isKinematic, but it doesn't stop my player from getting through the cube for some reason.
I have read some sites about problems like this, but nothing helped yet.
It would be great if you can give me any code improvements :)
EDIT1:
Sorry, for answering so late, I couldn't do anything with my game in the last few days. Today I have tried to do something with raycasts, you can see my code, for my first try just in the update method:
void Update () {
if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) {
if (perc == 1) {
lerpTime = 1;
currentLerpTime = 0;
firstInput = true;
justJump = true;
}
}
startPos = gameObject.transform.position;
/* if (Input.GetButtonDown("right") && gameObject.transform.position == endPos) {
//endPos = new Vector3(transform.position.x + 0.5f, transform.position.y, transform.position.z);
}
if (Input.GetButtonDown("left") && gameObject.transform.position == endPos) {
endPos = new Vector3(transform.position.x - 0.5f, transform.position.y, transform.position.z);
}*/
Vector3 fwd = player.transform.TransformDirection(Vector3.forward);
RaycastHit objectHit;
if (Physics.Raycast(player.transform.position, fwd, out objectHit, 2)) {
if (objectHit.collider.tag == "Wall") {
Debug.Log("WALL RAYCAST HIT!");
}
}
if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));
}
if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) {
//endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, -1f));
}
if (firstInput == true) {
currentLerpTime += Time.deltaTime * 5;
perc = currentLerpTime / lerpTime;
gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc);
if (perc > 0.8f) {
perc = 1;
}
if (Mathf.Round(perc) == 1) {
justJump = false;
}
}
}
With this I can get the Debug Log WALL RAYCAST HIT 2-3 times at a time, but only once. As I move the character it won't appear again, for some reason (I think it should because the update method is called in every frame).
Although when I place it in the Input.GetButtonDown("up") method, it won't log anything:
if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
fwd = player.transform.TransformDirection(Vector3.forward);
if (Physics.Raycast(player.transform.position, fwd, out objectHit, 2)) {
if (objectHit.collider.tag == "Wall") {
Debug.Log("WALL RAYCAST HIT!");
}
}
endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));
}
When you update the transform.position you actually "teleport" yout object to the new position. Even when you do this smoothly, using something like the Lerp function, as you do on your move script, Unity understands that you are teleporting your object to a new coordinate.
This is not wrong, All games work like that. Functions like Lerp just create the ilusion of movement, so the player fell like the character actually moved from one point to another.
What is happening is that your script keeps telling the character to move to a new position, despite any objects on its path. The collision happens, but your Update function still places the character on ints new position.
I can think of two possible ways for you to solve this:
Create an OnCollisionEnter() function for your Move script that somehow stops your movement. By creating a flag like you did with the firstInput you could achieve this.
Instead of updating your transform.position you could use a rigidbody to handle the movement and collisions for your. This way, everytime you need to move your character you will need to add some velocity to the character rigidbody, instead of directly updating the transform.position.
Since your character doesn't move in a constant way, but in a "one step at a time" way, I think the first solution is a better suitted for you.
The code will be something like this
void OnCollisionenter(Collision collision)
{
collided = true;
}
and the end of your Move script should be updated to
if(!collided)
{
if (firstInput == true) {
currentLerpTime += Time.deltaTime * 5;
perc = currentLerpTime / lerpTime;
transform.position = Vector3.Lerp(startPos, endPos, perc);
if (perc > 0.8f) {
perc = 1;
}
if (Mathf.Round(perc) == 1) {
justJump = false;
}
}
}
else
{
// Remember to reset this when you stop your character
endPos = transform.position;
collided = false;
}
This time I couldn't test the code before writting it here, so you may need to do some changes before it works.
ps: I don't think you need your firstInput variable. Once it is set to true, you never set it to false again. Also, the Input.GetButtonDown() function will only return true on the first frame a button is pressed wich is what I guess you intended when you created firstInput.
ps2: My solution added a collided boolean attribute to your class, so don't forget to add a line private bool collided; with your other class attributes. Also, read that chapter about the state machine pattern I recommended you on your other question. Creating this kind of control attribute suach as the collided boolean is not a good practice and if you had implemented a state machine this could be avoided.
Hey I had a similar problem i was using an animated model from Mixamo.com and I notices that for some strange reason the character didn't collide with boundaries despite having collider, for some reason it didn't work until i added a CharacterController to my model instead of a collider just search for the CharacterController and add it as you would add any script or rigid body to your game object.
Hope it Works XD Greetings