My intention is to make my character wall jump/climb/slide, I got the sliding part working fine, but if he jumps while wall sliding, he should "bounce" back to the wall, the problem is that I can't balance the forces. In all tutorial I saw, it is simply a matter of detecting if the character is wall sliding, and if he is and he jumps, then you add a force oposite to the wall.
This is not working for me, because if I add enough force to make him jump, he goes way too fast and the player can barely see he jumped, he just sees that the character is now higher on the wall. If I add a smaller amount of force, it isn't enough to make a considerable jump and the player would have to hit space a thousand times to make him go up a few centimeters on the wall.
Any help is appreciated, I already tried a lot of things, even tried to freeze the controls, set gravity scale to 0 and make the character fo to the right points using MoveTowards, that is how desperate I am.
I'm also really new to Unity so I might be missing something really simple.
Here is a gif showing the character's behavior:
https://imgur.com/a/TgUHzP6
And here is the relevant parts of my character's script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TheBot : MonoBehaviour {
public float speed;
public int jumpForce;
public Transform groundCheck;
public Transform meleeCheck;
public Transform bulletSpawner;
public LayerMask layerGround;
public float meleeCoolDown;
public float meleeDamage;
private Rigidbody2D body;
private Animator anim;
private Dash dashController;
private Shooter shotController;
private float unloadWaitingTime = 3;
private float idleGunTime = 0;
private bool facingRight = true;
private bool onGround = true;
private bool jumping = false;
private bool attacking = false;
private bool dead = false;
private bool isGunLoaded = false;
private bool isGunLoading = false;
private bool isGunUnloading = false;
private bool takingDamage = false;
private bool dashing = false;
private bool isWallSliding = false;
private float wallJumpTime = 0f;
private Vector3[] wallJumpControlPoint;
// Use this for initialization
void Start () {
body = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
dashController = GetComponent<Dash>();
shotController = GetComponent<Shooter>();
}
// Update is called once per frame
void Update () {
PlayAnimations();
CheckIfGrounded();
checkIfWallSliding();
dashing = dashController.IsDashing();
if (Input.GetButtonDown("Jump") && (onGround || isWallSliding) && !isGunLoading && !jumping && !takingDamage){
jumping = true;
wallJumpControlPoint = new Vector3[3];
wallJumpControlPoint[0] = body.position;
wallJumpControlPoint[1] = new Vector3(body.position.x +4, body.position.y + 2);
wallJumpControlPoint[2] = new Vector3(body.position.x, body.position.y + 4);
}
if (Input.GetButtonDown("Melee") && !attacking && !isGunLoading){
Attack();
}
if(Input.GetButtonDown("Ranged") && !attacking && !isGunLoading && onGround){
Shoot();
}
if(Input.GetButtonDown("Dash") && !attacking && !isGunLoading && onGround){
dashController.DashTo(facingRight? Dash.RIGHT : Dash.LEFT);
}
if(isGunLoaded){
idleGunTime += Time.deltaTime;
if (idleGunTime >= unloadWaitingTime){
UnloadGun();
}
}
}
void FixedUpdate(){
if(!takingDamage){
float move = Input.GetAxis("Horizontal");
//while charachter is wall sliding, slowly fall
if (isWallSliding){
body.velocity = new Vector2(body.velocity.x, -0.7f);
}
if(!dashing){
if(onGround){
//if not dashing on on ground, walk with normal speed
body.velocity = new Vector2(move * speed, body.velocity.y);
} else {
//if character is not on ground, reduce the speed so he doesn't jump too far away
body.velocity = new Vector2(move * (speed * 0.7f), body.velocity.y);
}
}
if((move < 0 && facingRight) || (move > 0 && !facingRight) ){
//control direction character is facing
Flip();
}
if (jumping){
if(isWallSliding){
body.velocity = new Vector2(30, 20);
} else {
body.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)){
//if is moving while jumping, reduce jump height
body.velocity = new Vector2(body.velocity.x, body.velocity.y*0.8f);
}
onGround = false;
jumping = false;
}
}
}
void CheckIfGrounded(){
onGround = false;
Collider2D[] collisionResults = new Collider2D[2];
int objectsBeneath = Physics2D.OverlapBoxNonAlloc(groundCheck.position, new Vector2(0.9f, 0.3f), 0.0f, collisionResults, layerGround);
for (int i=0; i <objectsBeneath; i++ ){
if (!GameObject.ReferenceEquals(gameObject, collisionResults[i].gameObject)){
onGround = true;
}
}
}
void checkIfWallSliding(){
if (!onGround){
RaycastHit2D[] ray = new RaycastHit2D[1];
int totalRayHits = Physics2D.LinecastNonAlloc(bulletSpawner.position, body.position, ray, 1 << LayerMask.NameToLayer("SolidGround"));
bool wallFound = totalRayHits > 0 && ray[0].collider.gameObject.tag == "SolidGround";
isWallSliding = wallFound && ( (facingRight && Input.GetKey(KeyCode.RightArrow)) || (!facingRight && Input.GetKey(KeyCode.LeftArrow))) ;
} else {
isWallSliding = false;
if (body.velocity.y > 10){
body.velocity = new Vector2(body.velocity.x, 5);
}
}
}
public void Die(){
dead = true;
}
}
As you've attempted before, you will need to reduce your horizontal jump acceleration/velocity on the jump.
When you wall jump, you'll be pressing towards the wall. And as your code is currently, while you are in the air, your horizontal velocity is set to be in the direction you press. This makes any horizontal movement from the wall jump very hard to see, unless it's large enough to push you very far in one frame.
This (as well as the change we discussed in the comments) is why your previous attempts with low walljump magnitudes didn't work.
To fix this, you have to change how your air control works. One way of going about it is making it add a clamped modifier to your horizontal velocity instead of setting it directly to the target velocity.
if(!dashing){
if(onGround){
//if not dashing on on ground, walk with normal speed
body.velocity = new Vector2(move * speed, body.velocity.y);
} else {
//if character is not on ground, reduce the speed so he doesn't jump too far away
float airControlAccelerationLimit = 0.5f; // Higher = more responsive air control
float airSpeedModifier = 0.7f; // the 0.7f in your code, affects max air speed
float targetHorizVelocity = move
* speed
* airSpeedModifier; // How fast we are trying to move horizontally
float targetHorizChange = targetHorizVelocity
- body.velocity.x; // How much we want to change the horizontal velocity
float horizChange = Mathf.Clamp(
targetHorizChange ,
-airControlAccelerationLimit ,
airControlAccelerationLimit ); // How much we are limiting ourselves
// to changing the horizontal velocity
body.velocity = new Vector2(body.velocity.x + horizChange, body.velocity.y);
}
}
Here it is, in your code, along with making sure we only update velocity once OR use AddForce per FixedUpdate call. And we also change the wallsliding slowdown code to only activate if the player is about to go down faster than the wallslide speed.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TheBot : MonoBehaviour {
public float speed;
public int jumpForce;
public Transform groundCheck;
public Transform meleeCheck;
public Transform bulletSpawner;
public LayerMask layerGround;
public float meleeCoolDown;
public float meleeDamage;
private Rigidbody2D body;
private Animator anim;
private Dash dashController;
private Shooter shotController;
private float unloadWaitingTime = 3;
private float idleGunTime = 0;
private bool facingRight = true;
private bool onGround = true;
private bool jumping = false;
private bool attacking = false;
private bool dead = false;
private bool isGunLoaded = false;
private bool isGunLoading = false;
private bool isGunUnloading = false;
private bool takingDamage = false;
private bool dashing = false;
private bool isWallSliding = false;
private float wallJumpTime = 0f;
private Vector3[] wallJumpControlPoint;
// Use this for initialization
void Start () {
body = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
dashController = GetComponent<Dash>();
shotController = GetComponent<Shooter>();
}
// Update is called once per frame
void Update () {
PlayAnimations();
CheckIfGrounded();
checkIfWallSliding();
dashing = dashController.IsDashing();
if (Input.GetButtonDown("Jump") && (onGround || isWallSliding) && !isGunLoading && !jumping && !takingDamage){
jumping = true;
wallJumpControlPoint = new Vector3[3];
wallJumpControlPoint[0] = body.position;
wallJumpControlPoint[1] = new Vector3(body.position.x +4, body.position.y + 2);
wallJumpControlPoint[2] = new Vector3(body.position.x, body.position.y + 4);
}
if (Input.GetButtonDown("Melee") && !attacking && !isGunLoading){
Attack();
}
if(Input.GetButtonDown("Ranged") && !attacking && !isGunLoading && onGround){
Shoot();
}
if(Input.GetButtonDown("Dash") && !attacking && !isGunLoading && onGround){
dashController.DashTo(facingRight? Dash.RIGHT : Dash.LEFT);
}
if(isGunLoaded){
idleGunTime += Time.deltaTime;
if (idleGunTime >= unloadWaitingTime){
UnloadGun();
}
}
}
void FixedUpdate(){
if(!takingDamage){
float move = Input.GetAxis("Horizontal");
//while charachter is wall sliding, slowly fall
if (isWallSliding && !jumping && body.velocity.y < -0.7f){
body.velocity = new Vector2(body.velocity.x, -0.7f)
}
if(!dashing){
if(onGround){
//if not dashing on on ground, walk with normal speed
body.velocity = new Vector2(move * speed, body.velocity.y);
} else {
//if character is not on ground, reduce the speed so he doesn't jump too far away
float airControlAccelerationLimit = 0.5f; // Higher = more responsive air control
float airSpeedModifier = 0.7f; // the 0.7f in your code, affects max air speed
float targetHorizVelocity = move
* speed
* airSpeedModifier; // How fast we are trying to move horizontally
float targetHorizChange = targetHorizVelocity
- body.velocity.x; // How much we want to change the horizontal velocity
float horizChange = Mathf.Clamp(
targetHorizChange ,
-airControlAccelerationLimit ,
airControlAccelerationLimit ); // How much we are limiting ourselves
// to changing the horizontal velocity
body.velocity = new Vector2(body.velocity.x + horizChange, body.velocity.y);
}
}
if((move < 0 && facingRight) || (move > 0 && !facingRight) ){
//control direction character is facing
Flip();
}
if (jumping){
if(isWallSliding){
body.velocity = new Vector2(body.velocity.x + 0.25f * jumpForce, jumpForce);
} else {
body.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)){
//if is moving while jumping, reduce jump height
body.velocity = new Vector2(body.velocity.x, body.velocity.y*0.8f);
}
onGround = false;
jumping = false;
}
}
}
void CheckIfGrounded(){
onGround = false;
Collider2D[] collisionResults = new Collider2D[2];
int objectsBeneath = Physics2D.OverlapBoxNonAlloc(groundCheck.position, new Vector2(0.9f, 0.3f), 0.0f, collisionResults, layerGround);
for (int i=0; i <objectsBeneath; i++ ){
if (!GameObject.ReferenceEquals(gameObject, collisionResults[i].gameObject)){
onGround = true;
}
}
}
void checkIfWallSliding(){
if (!onGround){
RaycastHit2D[] ray = new RaycastHit2D[1];
int totalRayHits = Physics2D.LinecastNonAlloc(bulletSpawner.position, body.position, ray, 1 << LayerMask.NameToLayer("SolidGround"));
bool wallFound = totalRayHits > 0 && ray[0].collider.gameObject.tag == "SolidGround";
isWallSliding = wallFound && ( (facingRight && Input.GetKey(KeyCode.RightArrow)) || (!facingRight && Input.GetKey(KeyCode.LeftArrow))) ;
} else {
isWallSliding = false;
}
}
public void Die(){
dead = true;
}
}
Related
In the example video, when the player walks off the ledge he immediately transitions into a slowed down fall state but when the player jumps, he's allowed to fall quickly unless there is no platform underneath him, in which case he transitions into the slower fall state. How can I achieve this in my game?
https://www.youtube.com/watch?v=PZfdQPAM9OE&feature=youtu.be
Thanks for the help!
There so many way, I'll give you one simple example:
You need set up a simple scene where you have a character (e.g capsule) with rigidbody (Use Gravity set to false) and collider, and many grounds (e.g cube) with collider, and set the tag of all grounds to ground, then change the view to 2D
using UnityEngine;
public class Test : MonoBehaviour
{
public float slowFallSpeed = 1f;
public float normalFallSpeed = 3f;
public float runSpeed = 5f;
bool aboveGround = false;
bool touchGround = false;
bool inFall = false;
bool inJump = false;
const string k_Ground = "ground"; // Tag of ground object.
float maxRaycastDist = 2;
float currentFallSpeed = 0f;
Rigidbody rg;
void Start()
{
rg = GetComponent<Rigidbody>();
}
void OnCollisionEnter(Collision col)
{
if (col.transform.CompareTag(k_Ground) && aboveGround)
touchGround = true;
}
void OnCollisionExit(Collision col)
{
if (col.transform.CompareTag(k_Ground))
touchGround = false;
}
void FixedUpdate()
{
// Check if character above the ground
RaycastHit[] hits = Physics.RaycastAll(transform.position, Vector3.down, maxRaycastDist);
aboveGround = false;
foreach (var hit in hits)
{
if (hit.transform.CompareTag(k_Ground))
{
aboveGround = true;
break;
}
}
// Move
Vector3 moveDir = Vector3.zero;
if (Input.GetKey("d"))
moveDir += new Vector3(1f, 0f);
if (Input.GetKey("a"))
moveDir += new Vector3(-1f, 0f);
inJump = Input.GetKey("w") && !inFall;
if (inJump)
moveDir += new Vector3(0f, 1f);
rg.position += moveDir.normalized * runSpeed * Time.fixedDeltaTime;
// Fall
if (!touchGround && !inFall && !inJump)
{
inFall = true;
currentFallSpeed = aboveGround ? normalFallSpeed : slowFallSpeed;
}
else if (touchGround && inFall)
{
inFall = false;
currentFallSpeed = 0f;
}
if (currentFallSpeed != 0f)
rg.position += Vector3.down * currentFallSpeed * Time.fixedDeltaTime;
}
}
You could using different settings and differen component or in the 2D space, but logic should be the same
I am creating a clone of Billiards and I cannot work out how to stop the player from interacting with and launching the ball while it is still moving; below is my attempt. I have placed an if statement that checks whether the ball is moving on both the mouseDrag and mouseUp functions. I have also tried using isSleeping() but this caused the ball to not move at all.
If possible I would like to apply this method to all of the balls and not just the cue ball; so that all balls have to have stopped before any actions may happen. This is currently in my "player" script, if I should move it a GameManager script please let me know.
private void Update()
{
speed = rb.velocity.magnitude;
if (speed < 0.5)
{
rb.velocity = new Vector3(0, 0, 0);
}
}
void OnMouseDrag()
{
if (speed == 0)
{
mousePointB.GetComponent<SpriteRenderer>().enabled = true;
currDistance = Vector3.Distance(mousePointA.transform.position, transform.position);
if (currDistance <= 3f)
{
spaceLimit = currDistance;
}
else
{
spaceLimit = maxDistance;
}
shootPower = Mathf.Abs(spaceLimit) * shootPowervar;
Vector3 dimxy = mousePointA.transform.position - transform.position;
float difference = dimxy.magnitude;
mousePointB.transform.position = transform.position + ((dimxy / difference) * currDistance * -1);
mousePointB.transform.position = new Vector3(mousePointB.transform.position.x, mousePointB.transform.position.y, -0.8f);
shootDirection = Vector3.Normalize(mousePointA.transform.position - transform.position);
}
else
{
}
}
void OnMouseUp()
{
if (speed == 0)
{
mousePointB.GetComponent<SpriteRenderer>().enabled = false;
arrow.GetComponent<SpriteRenderer>().enabled = false;
circle.GetComponent<SpriteRenderer>().enabled = false;
Vector3 push = shootDirection * shootPower * -1;
GetComponent<Rigidbody2D>().AddForce(push, ForceMode2D.Impulse);
}
else
{
}
}
if your test speed == 0 is not functional, you could record the last position of the ball, and set a boolean isMoving = true, if actual position of ball is different thant the last, then record the lastposition and so on
Vector3 LastPosition;
bool isMoving;
void Update()
{
isMoving = BallPosition == LastPosition;
:
:
}
void OnMOuseDrag()
{
if(!isMoving) return;
}
void OnMOuseUp()
{
if(!isMoving) return;
}
So, when I start the game, my character can jump on the first platform (because that is the manually placed platform), but I cannot jump on the spawned floors. BTW I am able to run on the floors and I know my jump works correctly.
I have tried so many ways of collider detection I am going crazy and I know its a simple fix that I just can't figure out.
I expected my character to be able to jump on the duplicated platforms but the character just doesn't do anything at all.
If anyone is willing to take a look that would be very helpful. - Nick
P.S I know my code is messy.
CODE:
#Code that is on my player script#
using System;
using System.Diagnostics;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using TouchControlsKit;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Text;
using System.IO;
public class Attack : MonoBehaviour
{
const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded
[SerializeField] private LayerMask m_WhatIsGround;
[SerializeField] private Transform m_GroundCheck;
private bool m_Grounded;
public Collider2D objectCollider;
public Collider2D anotherCollider;
[Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f;
private Timer t;
private Timer a;
private float timeStamp;
private float die = 0;
public GameObject bullet;
private bool m_FacingRight = true;
public float move;
private Vector3 velocity = Vector3.zero;
public GameObject idle_0;
public playscript play;
public Transform player;
private Rigidbody2D m_Rigidbody2D;
[SerializeField] private float m_JumpForce = 200f;
bool swing = false;
bool isgrounded = false;
public bool canJump = false;
bool slide = false;
public Transform groundLayer; // Insert the layer here.
public Vector2 jumpHeight;
private Vector2 touchOrigin = -Vector2.one;
public Vector2 moveSpeed;
public bool run;
Collider2D m_Collider;
// variable to hold a reference to our SpriteRenderer component
private SpriteRenderer mySpriteRenderer;
// This function is called just one time by Unity the moment the component loads
private void Awake()
{
// get a reference to the SpriteRenderer component on this gameObject
mySpriteRenderer = GetComponent<SpriteRenderer>();
animator.SetBool("death", false);
}
public Animator animator;
Animator anim;
int swingHash = Animator.StringToHash("swing");
// Use this for initialization
void Start()
{
timeStamp = Time.time + 5;
m_Collider = GetComponent<Collider2D>();
run = false;
m_Rigidbody2D = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
animator.SetBool("isgrounded", false);
isgrounded = false;
canJump = false;
animator.SetBool("swing", false);
}
private void FixedUpdate()
{
m_Grounded = false;
// The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
// This can be done using layers instead but Sample Assets will not overwrite your project settings.
Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
animator.SetBool("isgrounded", true);
m_Grounded = true;
}
}
// Update is called once per frame
void Update()
{
anotherCollider = GameObject.FindGameObjectWithTag("Ground").GetComponent<BoxCollider2D>();
objectCollider = GameObject.FindGameObjectWithTag("Player").GetComponent<CapsuleCollider2D>();
Vector3 targetVelocity = new Vector2(move * 2f, m_Rigidbody2D.velocity.y);
m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref velocity, m_MovementSmoothing);
animator.SetBool("run", true);
if (move > 0 && !m_FacingRight)
{
// ... flip the player.
Flip();
}
// Otherwise if the input is moving the player left and the player is facing right...
else if (move < 0 && m_FacingRight)
{
// ... flip the player.
Flip();
}
int horizontal = 0; //Used to store the horizontal move direction.
int vertical = 0; //Used to store the vertical move direction.
#if UNITY_STANDALONE || UNITY_WEBPLAYER
//Check if we are running on iOS, Android, Windows Phone 8 or Unity iPhone
#elif UNITY_IOS || UNITY_ANDROID || UNITY_WP8 || UNITY_IPHONE
//Check if Input has registered more than zero touches
if (Input.touchCount > 0)
{
//Store the first touch detected.
Touch myTouch = Input.touches[0];
//Check if the phase of that touch equals Began
if (myTouch.phase == TouchPhase.Began)
{
//If so, set touchOrigin to the position of that touch
touchOrigin = myTouch.position;
}
//If the touch phase is not Began, and instead is equal to Ended and the x of touchOrigin is greater or equal to zero:
else if (myTouch.phase == TouchPhase.Ended && touchOrigin.x >= 0)
{
//Set touchEnd to equal the position of this touch
Vector2 touchEnd = myTouch.position;
//Calculate the difference between the beginning and end of the touch on the x axis.
float x = touchEnd.x - touchOrigin.x;
//Calculate the difference between the beginning and end of the touch on the y axis.
float y = touchEnd.y - touchOrigin.y;
//Set touchOrigin.x to -1 so that our else if statement will evaluate false and not repeat immediately.
touchOrigin.x = -1;
//Check if the difference along the x axis is greater than the difference along the y axis.
if (Mathf.Abs(x) > Mathf.Abs(y))
//If x is greater than zero, set horizontal to 1, otherwise set it to -1
horizontal = x > 0 ? 1 : -1;
else
//If y is greater than zero, set horizontal to 1, otherwise set it to -1
vertical = y > 0 ? 1 : -1;
}
}
#endif
if (TCKInput.GetAction("jumpBtn", EActionEvent.Up))
{
animator.SetBool("jump", false);
}
if (TCKInput.GetAction("jumpBtn", EActionEvent.Down) && m_Grounded == true)
{
animator.SetBool("jump", true);
m_Grounded = false;
m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));
}
if (TCKInput.GetAction("fireBtn", EActionEvent.Down))
{
animator.SetBool("swing", true);
m_Collider.enabled = !m_Collider.enabled;
}
if (TCKInput.GetAction("fireBtn", EActionEvent.Up))
{
animator.SetBool("swing", false);
m_Collider.enabled = !m_Collider.enabled;
}
if (TCKInput.GetAction("slideBtn", EActionEvent.Down))
{
if (timeStamp <= Time.time)
{
animator.SetBool("slide", true);
GameObject b = (GameObject)(Instantiate(bullet, transform.position + transform.right * 1.5f, Quaternion.identity));
b.GetComponent<Rigidbody2D>().AddForce(transform.right * 1000);
timeStamp = Time.time + 5;
}
}
if (TCKInput.GetAction("slideBtn", EActionEvent.Up))
{
animator.SetBool("slide", false);
}
if (TCKInput.GetAction("right", EActionEvent.Press))
{
move = -1;
}
if (TCKInput.GetAction("right", EActionEvent.Up))
{
animator.SetBool("run", false);
}
if (TCKInput.GetAction("left", EActionEvent.Press))
{
move = 1;
}
if (TCKInput.GetAction("left", EActionEvent.Up))
{
animator.SetBool("run", false);
}
if (objectCollider.IsTouching(anotherCollider))
{
canJump = true;
}
else
{
canJump = false;
}
}
private void Flip()
{
// Switch the way the player is labelled as facing.
m_FacingRight = !m_FacingRight;
// Multiply the player's x local scale by -1.
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
void Hurt()
{
move = 4;
SceneManager.LoadScene(0);
}
protected void OnCollisionEnter2D(Collision2D collision)
{
EnemyHealth3 enemy = collision.collider.GetComponent<EnemyHealth3>();
if (enemy != null)
{
move = 0;
animator.SetBool("death", true);
m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));
StartCoroutine(ExecuteAfterTime(.1));
}
}
IEnumerator ExecuteAfterTime(double time)
{
yield return new WaitForSeconds((float)time);
Hurt();
}
}
#Code that is on the floor spawner script#
using UnityEngine;
using System.Collections;
public class Floor_Spawn_Script : MonoBehaviour
{
public GameObject[] obj;
private float oldPosition;
private float currentPosition;
private float ctr = 0;
private float inte = 10.19f;
// Use this for initialization
private void Start()
{
oldPosition = transform.position.x;
AddRoom(ctr * inte);
ctr += 1;
AddRoom(ctr * inte);
ctr += 1;
AddRoom(ctr * inte);
}
// Update is called once per frame
void Update()
{
currentPosition = transform.position.x;
if ((currentPosition - oldPosition) <= 9.595f)
{
AddRoom(ctr * inte);
oldPosition = transform.position.x;
ctr += 1;
}
}
void AddRoom(float roomCenter)
{
GameObject room = (GameObject)Instantiate(obj[Random.Range(0, obj.Length)]);
room.transform.position = new Vector3(roomCenter, 0f, 10f);
}
}```
Hi i have a scenario in which i need to limit the angle rotation for 3rd person controller.Present when i press left and right input keys it is turning 90degrees. I wish to rotate 45degrees. Could someone help me,at which line that angle rotation is happening.
Here my code :
public class ThirdPersonShooter : MonoBehaviour
{
public AnimationClip idleAnimation;
public AnimationClip walkAnimation;
public AnimationClip runAnimation;
public AnimationClip jumpPoseAnimation;
public float walkMaxAnimationSpeed = 0.75F;
public float trotMaxAnimationSpeed = 1F;
public float runMaxAnimationSpeed = 1F;
public float jumpAnimationSpeed = 1F;
public float landAnimationSpeed = 1F;
private Animation _animation;
enum CharacterState
{
Idle = 0,
Walking = 1,
Trotting = 2,
Running = 3,
Jumping = 4,
}
private CharacterState _characterState;
// The speed when walking
public float walkSpeed = 2.0F;
// after trotAfterSeconds of walking we trot with trotSpeed
public float trotSpeed = 4.0F;
// when pressing "Fire3" button (cmd) we start running
public float runSpeed = 6.0F;
public float inAirControlAcceleration = 3.0F;
// How high do we jump when pressing jump and letting go immediately
public float jumpHeight = 0.5F;
// The gravity for the character
public float gravity = 20.0F;
// The gravity in controlled descent mode
public float speedSmoothing = 10.0F;
public float rotateSpeed = 500.0F;
public float trotAfterSeconds = 3.0F;
public bool canJump = true;
private float jumpRepeatTime = 0.05F;
private float jumpTimeout = 0.15F;
private float groundedTimeout = 0.25F;
// The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around.
private float lockCameraTimer = 0.0F;
// The current move direction in x-z
private Vector3 moveDirection = Vector3.zero;
// The current vertical speed
private float verticalSpeed = 0.0F;
// The current x-z move speed
private float moveSpeed = 0.0F;
// The last collision flags returned from controller.Move
private CollisionFlags collisionFlags;
// Are we jumping? (Initiated with jump button and not grounded yet)
private bool jumping = false;
private bool jumpingReachedApex = false;
// Are we moving backwards (This locks the camera to not do a 180 degree spin)
private bool movingBack = false;
// Is the user pressing any keys?
private bool isMoving = false;
// When did the user start walking (Used for going into trot after a while)
private float walkTimeStart = 0.0F;
// Last time the jump button was clicked down
private float lastJumpButtonTime = -10.0F;
// Last time we performed a jump
private float lastJumpTime = -1.0F;
// the height we jumped from (Used to determine for how long to apply extra jump power after jumping.)
private float lastJumpStartHeight = 0.0F;
private Vector3 inAirVelocity = Vector3.zero;
private float lastGroundedTime = 0.0F;
private bool isControllable = true;
// Use this for initialization
void Awake()
{
moveDirection = transform.TransformDirection(Vector3.forward);
_animation = GetComponent<Animation>();
if (!_animation)
Debug.Log("The character you would like to control doesn't have animations. Moving her might look weird.");
/*
public AnimationClip idleAnimation;
public AnimationClip walkAnimation;
public AnimationClip runAnimation;
public AnimationClip jumpPoseAnimation;
*/
if (!idleAnimation)
{
_animation = null;
Debug.Log("No idle animation found. Turning off animations.");
}
if (!walkAnimation)
{
_animation = null;
Debug.Log("No walk animation found. Turning off animations.");
}
if (!runAnimation)
{
_animation = null;
Debug.Log("No run animation found. Turning off animations.");
}
if (!jumpPoseAnimation && canJump) {
_animation = null;
Debug.Log("No jump animation found and the character has canJump enabled. Turning off animations.");
}
}
void UpdateSmoothedMovementDirection()
{
Transform cameraTransform = Camera.main.transform;
bool grounded = IsGrounded();
// Forward vector relative to the camera along the x-z plane
Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);
forward.y = 0;
forward = forward.normalized;
// Right vector relative to the camera
// Always orthogonal to the forward vector
Vector3 right = new Vector3(forward.z, 0, -forward.x);
float v = Input.GetAxisRaw("Vertical");
float h = Input.GetAxisRaw("Horizontal");
// Are we moving backwards or looking backwards
if (v < -0.2f)
movingBack = true;
else
movingBack = false;
bool wasMoving = isMoving;
isMoving = Mathf.Abs(h) > 0.1f || Mathf.Abs(v) > 0.1f;
// Target direction relative to the camera
Vector3 targetDirection = h * right + v * forward;
// Grounded controls
if (grounded)
{
// Lock camera for short period when transitioning moving standing still
lockCameraTimer += Time.deltaTime;
if (isMoving != wasMoving)
lockCameraTimer = 0.0f;
// We store speed and direction seperately,
// so that when the character stands still we still have a valid forward direction
// moveDirection is always normalized, and we only update it if there is user input.
if (targetDirection != Vector3.zero)
{
// If we are really slow, just snap to the target direction
if (moveSpeed < walkSpeed * 0.9f && grounded)
{
moveDirection = targetDirection.normalized;
}
// Otherwise smoothly turn towards it
else
{
moveDirection = Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000);
moveDirection = moveDirection.normalized;
}
}
// Smooth the speed based on the current target direction
float curSmooth = speedSmoothing * Time.deltaTime;
// Choose target speed
//* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways
float targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0f);
_characterState = CharacterState.Idle;
// Pick speed modifier
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
{
targetSpeed *= runSpeed;
_characterState = CharacterState.Running;
}
else if (Time.time - trotAfterSeconds > walkTimeStart)
{
targetSpeed *= trotSpeed;
_characterState = CharacterState.Trotting;
}
else
{
targetSpeed *= walkSpeed;
_characterState = CharacterState.Walking;
}
moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth);
// Reset walk time start when we slow down
if (moveSpeed < walkSpeed * 0.3f)
walkTimeStart = Time.time;
}
// In air controls
else
{
// Lock camera while in air
if (jumping)
lockCameraTimer = 0.0f;
if (isMoving)
inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration;
}
}
void ApplyJumping()
{
// Prevent jumping too fast after each other
if (lastJumpTime + jumpRepeatTime > Time.time)
return;
if (IsGrounded())
{
// Jump
// - Only when pressing the button down
// - With a timeout so you can press the button slightly before landing
if (canJump && Time.time < lastJumpButtonTime + jumpTimeout) {
verticalSpeed = CalculateJumpVerticalSpeed(jumpHeight);
SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
}
}
}
void ApplyGravity()
{
if (isControllable) // don't move player at all if not controllable.
{
// Apply gravity
bool jumpButton = Input.GetButton("Jump");
// When we reach the apex of the jump we send out a message
if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0f)
{
jumpingReachedApex = true;
SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
}
if (IsGrounded())
verticalSpeed = 0.0f;
else
verticalSpeed -= gravity * Time.deltaTime;
}
}
float CalculateJumpVerticalSpeed(float targetJumpHeight)
{
// From the jump height and gravity we deduce the upwards speed
// for the character to reach at the apex.
return Mathf.Sqrt(2 * targetJumpHeight * gravity);
}
void DidJump()
{
jumping = true;
jumpingReachedApex = false;
lastJumpTime = Time.time;
//lastJumpStartHeight = transform.position.y;
lastJumpButtonTime = -10;
_characterState = CharacterState.Jumping;
}
void Update()
{
if (!isControllable)
{
// kill all inputs if not controllable.
Input.ResetInputAxes();
}
if (Input.GetButtonDown("Jump"))
{
lastJumpButtonTime = Time.time;
}
UpdateSmoothedMovementDirection();
// Apply gravity
// - extra power jump modifies gravity
// - controlledDescent mode modifies gravity
ApplyGravity();
// Apply jumping logic
ApplyJumping();
// Calculate actual motion
Vector3 movement = moveDirection * moveSpeed + new Vector3(0, verticalSpeed, 0) + inAirVelocity;
movement *= Time.deltaTime;
// Move the controller
CharacterController controller = GetComponent<CharacterController>();
collisionFlags = controller.Move(movement);
// ANIMATION sector
if (_animation)
{
if (_characterState == CharacterState.Jumping)
{
if (!jumpingReachedApex)
{
_animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed;
_animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
_animation.CrossFade(jumpPoseAnimation.name);
}
else
{
_animation[jumpPoseAnimation.name].speed = -landAnimationSpeed;
_animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
_animation.CrossFade(jumpPoseAnimation.name);
}
}
else
{
if (controller.velocity.sqrMagnitude < 0.1f)
{
_animation.CrossFade(idleAnimation.name);
}
else
{
if (_characterState == CharacterState.Running)
{
_animation[runAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, runMaxAnimationSpeed);
_animation.CrossFade(runAnimation.name);
}
else if (_characterState == CharacterState.Trotting)
{
_animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, trotMaxAnimationSpeed);
_animation.CrossFade(walkAnimation.name);
}
else if (_characterState == CharacterState.Walking)
{
_animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, walkMaxAnimationSpeed);
_animation.CrossFade(walkAnimation.name);
}
}
}
}
// ANIMATION sector
// Set rotation to the move direction
if (IsGrounded())
{
transform.rotation = Quaternion.LookRotation(moveDirection);
}
else
{
Vector3 xzMove = movement;
xzMove.y = 0;
if (xzMove.sqrMagnitude > 0.001f)
{
transform.rotation = Quaternion.LookRotation(xzMove);
}
}
// We are in jump mode but just became grounded
if (IsGrounded())
{
lastGroundedTime = Time.time;
inAirVelocity = Vector3.zero;
if (jumping)
{
jumping = false;
SendMessage("DidLand", SendMessageOptions.DontRequireReceiver);
}
}
}
void OnControllerColliderHit(ControllerColliderHit hit)
{
// Debug.DrawRay(hit.point, hit.normal);
if (hit.moveDirection.y > 0.01f)
return;
}
float GetSpeed()
{
return moveSpeed;
}
public bool IsJumping()
{
return jumping;
}
bool IsGrounded()
{
return (collisionFlags & CollisionFlags.CollidedBelow) != 0;
}
Vector3 GetDirection()
{
return moveDirection;
}
public bool IsMovingBackwards()
{
return movingBack;
}
public float GetLockCameraTimer()
{
return lockCameraTimer;
}
bool IsMoving()
{
return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5f;
}
bool HasJumpReachedApex()
{
return jumpingReachedApex;
}
bool IsGroundedWithTimeout()
{
return lastGroundedTime + groundedTimeout > Time.time;
}
void Reset()
{
gameObject.tag = "Player";
}
}
There are two lines under Update() that handle rotation:
transform.rotation = Quaternion.LookRotation(moveDirection);
and
transform.rotation = Quaternion.LookRotation(xzMove);
Follow the variables moveDirection and xzMove to see how the values are actually determined. It should be pretty straight forward. Hint: moveDirection located in the function UpdateSmoothedMovementDirection(). moveDirection is also used to calculate xzMove using movement. The rest I leave up to you.
Edit: The section of code that actually processes movement is inside UpdateSmoothedMovementDirection(). Look down to if (grounded) --> if (targetDirection != Vector3.zero). It is this area that processes movement. It is the if (targetDirection < walkSpeed * 0.9f && grounded) where movement snaps at 90 degrees. This is the intended function.
I swapped that code out with the code in the else statement, and at slow speeds the avatar moved more naturally. The avatar will only walk at 45 degrees when either both horizontal and vertical are toggled simultaneously. In other words, pressing up + left, or down + right, etc.
If you don't want the snap behavior, just use the code in the else statement and delete the conditional statements. Then your avatar will always turn smoothly.
I'm working on a project where I'm trying to make my character move by jumping at an angle. Right now during the frame updates, the character will pivot back and forth and when the right key is pressed, they will jump. This code causes them to jump at an angle, but they always return to their original position.
Additionally, I have two characters who start on opposite sides of the stage, but when I start the game they teleport to the same position. I've spent a lot of time reviewing my code but I can't seem to get this to work. Any help you can provide?
using UnityEngine;
using System.Collections;
public class Freg : MonoBehaviour {
public GameObject Tounge;
public float gravity;
public float tempScale = 1;
public float MaxJump = 8f;
public float MinJump = 0.1f;
static float yVector = 0;
static float xVector = 0;
static bool grounded = true;
bool isleft = false;
Vector3 farthestleft;
Vector3 farthestright;
// Use this for initialization
void Start () {
farthestleft = new Vector3 (-33.7f, 50.2f, 24.8f);
farthestright = new Vector3 (22.56f, 54.83f, -15.12f);
}
void OnTriggerEnter (Collider other) {
if (other.GetComponent<Collider> ().tag == "Ground") {
grounded = true;
yVector = 0;
//xVector = 0;
Vector3 onGround = new Vector3 (transform.position.x, -4.86f, transform.position.z);
transform.position = onGround;
} else
grounded = false;
}
// Update is called once per frame
void Update () {
/*if (Input.GetKey (KeyCode.UpArrow) == true) {
Tounge.transform.localScale.Set (1, 0.5f, 1);
} else {
Tounge.transform.localScale.Set (1, 1, 1);
}*/
if (grounded == false) {
yVector -= gravity;
}
if (Input.GetKeyDown (KeyCode.UpArrow) == true && grounded == true) {
MinJump += 0.5f;
} else if (MinJump > 0.1f){
yVector += MinJump;
xVector += MinJump;
MinJump = 0.1f;
grounded = false;
}
Vector3 stuff = new Vector3 (transform.localPosition.y + xVector, transform.position.y + yVector, transform.position.z);
transform.position = stuff;
float t = Mathf.PingPong (Time.time * 0.5f * 2.0f, 1.0f);
transform.eulerAngles = Vector3.Lerp (farthestright, farthestleft, t);
}
}
it looks like you should update the current position during the if statements, rather than after that way on each update, the actual position is moving based on the decision rather than just the end of the loop.