XNA - Hold longer to jump higher - c#

I'm looking for a simple method for my game, so that when you hold down the space bar, you jump higher. When you 'tap' you don't jump to maximum height. There would need to be a max, but yeah, I don't know how to go about programming this.
Anyhelp, very appreciated. Feedback will be given. Thanks.

In your update function that handles jumping, you could have it keep track of how long the character has been off the ground and have it's upward velocity stop increasing after an amount of time.
For instance, something like the following should work
class Player
{
private const int gravity = 2; //force of gravity on the object
private const int maxHeight = 5; //change as needed
private const int msecsToMax = 1500; //change as needed
private int yPos = 0;
private int timeOffGround = 0;
private yVel = 0;
//other functions and stuff
void update(GameTime gt)
{
//check if the player is on the ground and update as necessary
if(isOnGround())
timeOffGround = 0;
else
timeOffGround += gt.ElapsedGameTime.TotalMilliseconds;
//update the player's velocity
yVel -= isOnGround() ? 0 : gravity; //no velocity when on the ground
if(Keyboard.GetState().IsKeyDown(Keys.SPACE) && timeOffGround < msecsToMax))
yVel += (maxHeight / msecToMax);
yPos += yVel;
}
}

During the accent of a jump, the Y velocity is completely
overridden by a power curve. During the decent, gravity takes
over. The jump velocity is controlled by the jumpTime field
which measures time into the accent of the current jump.
First off you will need some simple global variables,
public bool isJumping; //Is the player in a jump?
private bool wasJumping; //Did the player just exit a jump?
private float jumpTime; //Time the player has been in a jump (Useful for adding a power curve or to max out on jump height)
MaxJumpTime = .8f; //If you want to max out a jump, otherwise remove the relevant parts of the code
JumpLaunchVelocity = -3000.0f; //How much velocity to "jump" with, this may depend on your speed of your player, so it will need some ajustment
Here is the function that does most of the work:
private float DoJump(float velocityY, GameTime gameTime)
{
// If the player wants to jump
if (isJumping)
{
// Begin or continue a jump
if ((!wasJumping && IsOnGround) || jumpTime > 0.0f)
{
//Do things like animate, or play a sound here
jumpTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
}
// If we are in the ascent of the jump
if (0.0f < jumpTime && jumpTime <= MaxJumpTime)
{
// Fully override the vertical velocity with a power curve that gives players more control over the top of the jump (If you dont want this you can remove the Math.Pow)
velocityY = JumpLaunchVelocity * (1.0f - (float)Math.Pow(jumpTime / MaxJumpTime, JumpControlPower));
}
else
jumpTime = 0.0f; // Reached the apex of the jump
}
else
{
// Continues not jumping or cancels a jump in progress
jumpTime = 0.0f;
}
wasJumping = isJumping;
return velocityY;
}
In your update when you calculate position and stuff:
velocity.Y = DoJump(velocity.Y, gameTime);
Take a look at the Platformer Starter Kit if you run into any problems!

Related

How can I add Jump Buffer after a Double Jump for 2D platformer in Unity?

**
I'm trying to double jump mechanic for Unity 2D platformer game. What I want is when the character has finished the double jump and right before it landed, if we hit the any Jump button, the character will still know it is the jump input. The Coyote Jump work just fine but the Buffer Jump is not **
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fox2 : MonoBehaviour {
Rigidbody2D rb;
Animator animator;
//Public Fields
[Range(0, 10f)] public float runSpeed=10f;
[Range(0, 300f)]public float jumpForce=200.0f;
#region private fields
// A small amount of time that player is allowed to jump after leaving a platform
private float coyoteTime = 0.25f;
private float coyoteTimeCounter;
// A small amount of time to detect whether player presses the Jump Buttons or not
private float bufferTime = 0.2f;
private float bufferTimeCounter= 0f;
#endregion
#region SerializeField
[SerializeField] Collider2D headCollider;
[SerializeField] Collider2D crouchingCollider;
[SerializeField] Transform groundCheckCollider;
[SerializeField] Transform ceilingCheckCollider;
[SerializeField] LayerMask groundLayer;
[SerializeField] LayerMask groundLayer2;// High platform
[SerializeField] int totalJumps;
#endregion
#region Variables
int availableJumps;
// Change the current x-axis position of the character
float horizontalValue;
// Change the value of the speed when the player is running
float runSpeedModifier=2f;
// Change the value of the speed when the player is running
float crouchSpeedModifier=0.3f;
// Change the power of the normal jump
float lowJumpForceModifier=0.22f;
// The wide of "groundCheckCollider" will use
float groundCheckRadius=0.5f;
// The wide of "ceilingCheckCollider" will use
float ceilingCheckRadius=0.2f;
// By default, the Fox will facing to the right side of the screen
bool isFacingRight=true;
// If the Fox is on the walking state, he will be changed to running
bool isRunning;
// Check if the Fox is standing on the ground
bool isGrounded;
// Check if the Fox was standing on the ground
bool wasGrounded;
// Check if the Fox is underneath a platform
bool isCeiling;
// Check if the Fox is able to crouch if he is on the ground
bool isCrouching;
bool isJumping;
// the value to indicate if player can do Multiple Jumps or not
bool multipleJumps;
#endregion
// Start is called before the first frame update
void Awake() {
rb=GetComponent<Rigidbody2D>();
animator=GetComponent<Animator>();
}
// Update is called once per frame
// Update will get input from the player
void Update() {
#region Move Input Mechanics
//Walk and Run input
horizontalValue=Input.GetAxisRaw("Horizontal");
if(Input.GetKeyDown(KeyCode.LeftShift))
isRunning=true;
if(Input.GetKeyUp(KeyCode.LeftShift))
isRunning=false;
#endregion
if(isGrounded)
coyoteTimeCounter = coyoteTime;
else coyoteTimeCounter -= Time.deltaTime;
if(availableJumps == 0)
bufferTimeCounter = bufferTime;
else bufferTimeCounter -= Time.deltaTime;
#region Jump Input Mechanics
if(Input.GetButtonDown("Jump"))
Jump();
if(Input.GetButtonUp("Jump") && rb.velocity.y > 0)
lowJump();
#endregion
#region Crouch Input Mechanics
if(Input.GetButtonDown("Crouch"))
isCrouching=true;
else if(Input.GetButtonUp("Crouch"))
isCrouching=false;
#endregion
}
// Check if the character is standing on the ground or not
void GroundCheck() {
wasGrounded = isGrounded;
isGrounded=false;
// Create a collider with the position of GroundCheckCollider (underneath the Fox), Radius: 0.5,
// and only tell the character is on the ground when he standing on the sorted ground layers
Collider2D[] colliders=Physics2D.OverlapCircleAll(groundCheckCollider.position, groundCheckRadius, groundLayer);
// If the colliding area between the GroundCheckCollider and the SortedGroundLayer is above 0,
// the character is on the ground
if(colliders.Length> 0)
{
isGrounded=true;
if(!wasGrounded)
{
availableJumps = totalJumps;
multipleJumps=false;
}
}
// if the Player is not on the ground, play the Jumping animation
// If the player is on the ground, disable the Jumping animation
animator.SetBool("Jumping", !isGrounded);
}
#region Jumping mechanics
// This section will take care of the normal jumps and multiple jumps
void Jump()
{
#region Initial Jumps Mechanics
// If the character is not on the ground and he ism't crouching
// let him do the initial jump
if(!isCrouching && (isGrounded || bufferTimeCounter >= 0f)) {
// Increase the y velocity by the amount of "jumpForce", keep x velocity the same
rb.velocity = Vector2.up * jumpForce;
// After the initial, set the MultipleJumps to true so he can jump multiple times if he wishes to
multipleJumps= true;
// Minus the number of jumps he already do the Initial Jump
availableJumps--;
bufferTimeCounter = 0f;
// Add Jumping animation to the character
animator.SetBool("Jumping", true);
Debug.Log("Initial Jump");
}
#endregion
else
{
#region Coyote Jumps Mechanics
// But if the character is on the edge of a platform but still want to jump,
// change the initial jump into the coyote ones.
if(!isCrouching && coyoteTimeCounter> 0f)
{
// Increase the y velocity by the amount of "jumpForce", keep x velocity the same
rb.velocity = Vector2.up * jumpForce;
// The same with the Initial Jump
multipleJumps = true;
// Minus the number of jumps he already do the Coyote Jump as the Initial ones.
availableJumps--;
// Add Jumping animation to the character
animator.SetBool("Jumping", true);
Debug.Log("Coyote Jump");
}
#endregion
#region Multiple Jump Mechanics
// After the Initial Jump or the Coyote Jump,
// the character will be able to perform the Multiple Jump
// as long as the number of the availableJumps is greater than 0
else if(!isCrouching && availableJumps> 0 && multipleJumps)
{
// Increase the y velocity by the amount of "jumpForce", keep x velocity the same
rb.velocity = Vector2.up * jumpForce;
// Keep minus the number of availableJumps while he do the Multiple Jumps
availableJumps--;
// Add Jumping animation to the character
animator.SetBool("Jumping", true);
Debug.Log("Multiple Jump");
}
#endregion
}
}
// This section will take care of the Low Jump
void lowJump() {
// "Lower Jump" or "Jump Cut" Mechanics
// if the character is on midair and we released the Jump button, reduce the velocity of y axis
// Decrease y velocity by the amount of "jumpForce", keep x velocity the same
rb.velocity = Vector2.up * jumpForce * lowJumpForceModifier;
// Add Jumping animation to the character
animator.SetBool("Jumping", true);
}
#endregion
// FixedUpdate will apply the input to the game character regardless of the speed of the game
void FixedUpdate() {
GroundCheck();
Flip(horizontalValue);
Move(horizontalValue, isRunning, isCrouching);
// Get the current value of Y velocity in order to add jump animation base on the velocity
animator.SetFloat("YVelocity", rb.velocity.y);
}
void Move(float direction, bool runFlag, bool crouchFlag) {
#region Crouching Mechanics
// if the character is standing on the ground
if(isGrounded==true) {
// if the character is not crouching,
if(!crouchFlag)
{
// Check if the character is underneath a surface
if(Physics2D.OverlapCircle(ceilingCheckCollider.position, ceilingCheckRadius, groundLayer2))
{
// If yes, switch to crouching mode
crouchFlag = true;
}
}
// If the character is crouching, disable the headCollider.
// If not, reactive it
headCollider.enabled = !crouchFlag;
}
// Add the crouching animation to the character
animator.SetBool("Crouch", crouchFlag);
#endregion
#region Walking and Running Mechanics
// Push the character to the left or right depending on the input
// Character's normal speed
float walk=direction * runSpeed * Time.fixedDeltaTime * 100;
// If the character want to run and he is not crouching, increase the walking speed
if(runFlag==true && crouchFlag==false) walk *=runSpeedModifier;
// If the character is crouching, decrease the walking speed
if(crouchFlag==true) walk *=crouchSpeedModifier;
rb.velocity=new Vector2(walk, rb.velocity.y); //Change x velocity = "walk", keep y velocity the same
// Adding the Running Animation to the Character
animator.SetFloat("XVelocity", Mathf.Abs(rb.velocity.x));
#endregion
}
// Rotate the character base on the moving inputs
void Flip(float direction) {
// If the player is looking to right and want to turn left (clicked left)
if (isFacingRight && direction < 0) {
transform.localScale=new Vector3(-1, 1, 1);
isFacingRight=false;
}
// If the player is looking to left and want to turn right (clicked right)
if ( !isFacingRight && direction > 0) {
transform.localScale=new Vector3(1, 1, 1);
isFacingRight=true;
}
}
}
I would start with something like that
void GroundCheck(){
[...]
if(!wasGrounded)
{
availableJumps = totalJumps;
multipleJumps=false;
if(Time.time - _lastJumpButtonTime < 0.1f){
Jump();
}
}
[...]
}
void Jump(){
_lastJumpButtonTime = Time.time;
[...]
}

Reduce input sensitivity in unity

I've made an Isometric character controller so it can move and head on an isometric based perspective. The problem is that when I try to move using 2 keys (W + D, A + S...) and release those keys, the player tends to face the very last key that was released, so it is difficult to head a diagonal direction. This makes the character flip its rotation in the very last moment the keys are released.
I've been thinking of using a kind of sleep or coroutine checking if two keys were pressed and released in a short period of time just not rotate it.
There exist any not too rustic solution for this?
Here is my code (I just copied it from here: https://www.studica.com/blog/isometric-camera-unity)
private void SetIsometricDirections() {
vertical = Camera.main.transform.forward;
vertical.y = 0;
vertical = Vector3.Normalize(vertical);
horizontal = Quaternion.Euler(new Vector3(0, 90, 0)) * vertical;
}
private void Move() {
Vector3 horizontalMovement = horizontal * moveSpeed * Time.deltaTime * Input.GetAxis("HorizontalKey");
Vector3 verticalMovement = vertical * moveSpeed * Time.deltaTime * Input.GetAxis("VerticalKey");
Vector3 heading = Vector3.Normalize(horizontalMovement + verticalMovement);
Heading(heading);
transform.position += (horizontalMovement + verticalMovement);
}
private void Heading(Vector3 heading) {
transform.forward = heading;
}
The heading trick it's in the "Heading" method, obviously.
I finally found a solution.
I'll post it just in case any one else needs it in the future.
I calculate the current rotation based on the movement.
private void SetRotation() {
currentRotation = Quaternion.LookRotation(movement);
}
Then, I created a second Quaternion to store the last rotation if is not the same than the current. I also use a counter to store the time a rotation has been faced before stopping the movement or changing the direction.
private void CheckSameRotation() {
if (lastRotation != currentRotation || movement == Vector3.zero) {
sameRotationTime = 0;
lastRotation = currentRotation;
}
else {
sameRotationTime += Time.deltaTime;
}
}
Then, I used a bool to check if the time is high enough to make the rotation happen.
private void TimeAtSameRotation() {
canRotate = (sameRotationTime < 0.015f) ? false : true;
}
And then, I finally rotate the object if the movement is not zero and the condition "canRotate" is true.
private void Rotate() {
if (movement != Vector3.zero && canRotate) {
transform.rotation = currentRotation;
}
}

How can I flip a sprite of an AI enemy character to face the direction its moving in?

I'm trying to make a patrolling AI character that will move from point to point.
The patrol part works perfectly. However, the problem is that the sprite only faces right. When it turned the sprite stays facing the same direction.
I have tried to change the transform rotation using transform.rotate, transform.rotation, transform.Quaternion and making a variable to store the rotation value yet they all kick errors back. The errors are usually made from the rotate/rotation functions not being compatible with any of the attempts I have tried.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// To do:
/// - make rotation of enemy sprite work when reaching the end of patrol area
/// - create attack function
/// </summary>
public class Enemy : MonoBehaviour
{
public int health;
public float speed;
public GameObject bloodEffect;
public Transform[] moveSpots; //patrol spots
public float startWaitTime; //start countdown till move to next spot
private Rigidbody2D rb;
private Animator anim;
private int randomSpot; //number of patrol spots
private float waitTime; //how long enemy stays at patrol spot for
// Start is called before the first frame update
void Start()
{
waitTime = startWaitTime; //make waittime equal to startwaittime
anim = GetComponent<Animator>();
randomSpot = Random.Range(0, moveSpots.Length); //choose a random first spot
}
// Update is called once per frame
void Update()
{
Vector3 spriteRotation = new Vector3(0, randomSpot, 0);
transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, speed * Time.deltaTime); //move toward first patrol area
transform.eulerAngles = spriteRotation;
if (Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.5f) //asks if patrol point is further that .5f away from enemy
{
if (waitTime <= 0) //if waitTime less than or equal to 0
{
randomSpot = Random.Range(0, moveSpots.Length); //picks new patrol point
waitTime = startWaitTime; //restarts countdown clock
}
else
{
waitTime -= Time.deltaTime; //counts down clock till next point
}
}
if (health <= 0)
{
Destroy(gameObject);
}
}
public void TakeDamage(int damage)
{
Instantiate(bloodEffect, transform.position, Quaternion.identity);
Debug.Log("Blood effect played");
health -= damage;
Debug.Log("Damage Taken");
}
}
The expected results for this code is that a random point will be chosen and the AI will move toward that chosen point. Once there it will stay idle for a specified amount of time before turning and moving to a new spot.
The actual result is mostly the same as expected only the sprite does not turn around but instead continues to face to the right even when the AI is moving left.
Image of area
the enemy is the dark red cube, the movepoints are the points that the enemy patrols between. when it reaches the left point, he should turn to the right and go back but this is not what happens, instead he just moves back and forth with no rotation. ive tried the SpriteRenderer.flipX route and it only works one time and then sticks with that direction.
The SpriteRenderer Component has a Flip attribute you could use for this.
You can access it in code
SpriteRenderer.flipX = true;
It will only flip the sprite and won't change anything else, so double check if your colliders are still in the right space :) See more in the documentation
Good luck
randomSpot is an index not an angle. So using
transform.eulerAngles = new Vector3(0, randomSpot, 0);
doens't make any sense to me ...
Instead of rotating you could also flip the sprite/Image by using a negative scale like e.g.
// Update is called once per frame
private void Update()
{
// however you determin if facing left or right
// you e.g. simply check whether the target position
// is left or right of you
var difference = moveSpots[randomSpot].position - transform.position;
var isFacingRight = difference.x > 0;
if (isFacingRight && transform.localScale.x < 0
|| !isFacingRight && transform.localScale.x > 0)
{
FlipSprite();
}
}
private void FlipSprite()
{
// invert the local X-axis scale
transform.localScale = new Vector3(-spriteTransform.localScale.x, spriteTransform.localScale.y, spriteTransform.localScale.z);
}
Script used for the example
private void Update()
{
// works only in a ScreenOverlay Canvas
var targetPosition = Input.mousePosition;
var difference = targetPosition - transform.position;
var isFacingRight = difference.x > 0 ? true : false;
if (isFacingRight && transform.localScale.x < 0
|| !isFacingRight && transform.localScale.x > 0)
{
FlipSprite();
}
// simply only move left or right on the x-axis towards the mouse
transform.position = Vector3.MoveTowards(transform.position, new Vector3(targetPosition.x, 218, 0), Time.deltaTime * 100);
}
private void FlipSprite()
{
// invert the local X-axis scale
transform.localScale = new Vector3(-transform.localScale.x, transform.localScale.y, transform.localScale.z);
}
You can try:
if (moveSpot[randomSpot].transform.position.x > transform.position.x) {
transform.localScale = new Vector3(-1, 1, 1);
}
else {
transform.localScale = new Vector3(1, 1, 1);
}

c# Unity3D Special Falldamage

So i am coding in Unity3D and i need to make so that i loose half of my maximum health which is 100 if my jump is over 1.533287.
My problem is that my player can double jump and is supposed to land on platforms higher than the start place of the jump.
}
void Start()
{
}
public int doubleJump = 0;
public float speed = 6.0F;
public float jumpSpeed = 8.0F;
public float gravity = 20.0F;
public int health = 100;
public float maxHeight;
public float height;
public int maxHealth = 100;
private Vector3 moveDirection = Vector3.zero;
// Update is called once per frame
void Update()
{
CharacterController controller = GetComponent<CharacterController>();
if (controller.isGrounded)
{
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButtonDown("Jump"))
{
moveDirection.y = jumpSpeed;
}
doubleJump = 0;
}
if (!controller.isGrounded)
{
if (doubleJump == 0)
{
if (Input.GetButtonDown("Jump"))
{
moveDirection.y = jumpSpeed;
doubleJump = 1;
}
}
}
if (maxHeight < height) //This sets the maximum height
{
maxHeight = height;
}
height = transform.position.y;
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
I would modify your code to use your player's rigidbody.
For example... if the player's velocity.y is in the positives, then he's moving upwards.
If the player's velocity.y is in the negatives, then it means they are falling.
Make it so that if the velocity.y is below a certain value, then they take fall damage.
That way if you player doubles jumps towards a platform, when they land the velocity.y might be a small negative number. However if they jumped off of that high platform, they'd have a longer fall time which means a larger negative velocity.
Here's an example, although I don't know what scale you're working in so the numbers may be inaccurate for your scene.
Your player double jumps towards a platform, and when they reach their maximum height their velocity.y is now equal to 0.
As they start falling, velocity.y dips into the negatives. This means that when your player lands, they'll have a negative velocity. Let's say -5.
You can make your code say something similar to
if(playerRigidBody.velocity.y <= -10)
{
FallDamage();
}
So if your player has been falling for a little while, they'd take fall damage. However since when they landed on your platform at a velocity of -5 they wouldn't take fall damage... and if they jump off the platform and land on the ground below their velocity will more than likely be below -10 in the example.
Hopefully this helps you figure this out!

2D game platform camera goes up when player touches edges

I'm doing a 2D platform game where the player only climbs (y-axis).
What I'm trying to do is when I reach near to the top edge, my camera goes up a little bit so I can see more of the level.
I have this, but it's not working:
Public Transform player;
Void Start() { }
Void Update()
{
if (player.transform.position > Screen.height - 50)
{
transform.position.y += speed * Time.deltaTime;
}
}
Other Way is like this But not working more than once, i might need to set move = false; but dont know how without interupting Lerp:
float moveTime = 1f; // In seconds
float moveTimer = 0.0f; // Used for keeping track of time
bool moving = false; // Flag letting us know if we're moving
public float heightChange = 7.0f; // This is the delta
// These will be assigned when a collision occurs
Vector3 target; // our target position
Vector3 startPos; // our starting position
void Start()
{
}
void Update()
{
// If we're currently moving and the movement hasn't finished
if (moving && moveTimer < moveTime)
{
// Accumulate the frame time, making the timer tick up
moveTimer += Time.deltaTime;
// calculate our ratio ("t")
float t = moveTimer / moveTime;
transform.position = Vector3.Lerp(startPos, target, t);
}
else
{
// We either haven't started moving, or have finished moving
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (!moving)
{
// We set the target to be ten units above our current position
target = transform.position + Vector3.up * heightChange;
// And save our start position (because our actual position will be changing)
startPos = transform.position;
// Set the flag so that the movement starts
moving = true;
}
}
}
you are comparing two different things here. Screen.height is in pixels while player position is in world units. so lets assume your screen is 1024x768 you are checking if your player is above 718 which is a huge amount in world units.
What you have to do is convert one to the others unit and compare then for example with http://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html
Another thing i noticed is that this script is named player so i assume this is controlling your player object in which case
transform.position.y += speed * Time.deltaTime;
would only change your players position. To change the position of the main camera you could use:
Camera.main.transform.position += new Vector3(0f, speed * Time.deltaTime, 0f);
And lastly, always post the errors you get when asking questions, explain what you expect to happen and what actually happens.
You could try lerping the between positions eg.
transform.position = new trasform.lerp(transform.position, player.transform.position, speed*Time.DeltaTime);
just use the if statement to trigger a bool that then does the lerp, so the camera will move to what you need it to and not just when the player hits a certain point. Then when the camera is finished mooving, reset the bool ready for next time

Categories

Resources