Make character only can jump when touching the ground - unity3d

I want to make a character jump only when he is with his feet on the ground. I don't want him to be able to 'air-jump', so I came with this solution:
if (JumpButtonPressed()) {
if (GetComponent<BoxCollider2D>().IsTouchingLayers(LayerMask.NameToLayer("Ground"))) {
velocity.y = jumpForce;
}
}
The idea is that only when in touch with a "Ground" Layer, it can jump. But this is what happens:
It doesnt work just on his foot. If he is touching a platform by the side, it can jump as well. What could I do?

Use circle overlap with a position vector which is placed at the bottom on the player. Detect layer from there.
You may need to use different layer for platform if you want to write features like ledge grab, jump.

Create a bool isJumping and set it to true while in the air. When it reaches the ground - set it to false. Smth like that if your snippet is in Update():
bool isJumping = false;
if (JumpButtonPressed() && !isJumping) {
if (GetComponent<BoxCollider2D>().IsTouchingLayers(LayerMask.NameToLayer("Ground"))) {
velocity.y = jumpForce;
isJumping = true;
}
}
if (GetComponent<BoxCollider2D>().IsTouchingLayers(LayerMask.NameToLayer("Ground"))) {
isJumping = false;
}

Related

How to register a fall from height in unity 2D

So i'm working on a 2D game, first stage is a platformer so i'm trying to make it look nicer. I added a particle system with dust, so in case he falls down from height animation should be played. How do i register a fall from height to play the animation?
You can play animation on collision with the ground collider, when player's falling velocity is higher than 0. Using specific positive value may be nicer, cos it's gonna look like only achieving enough speed will spread dust.
I can see another way of doing this, but it takes more calculations:
To define the last position and current position of Y coordinates of the player.
If it is going down currentPos < lastPos
If it is going up currentPos > lastPos
public GameObject player;
public GameObject particleDust;
Vector3 lastPos;
Vector3 currentPos;
float _time = 0;
private bool up = false;
private bool down = false;
private bool equal = false;
void Awake()
{
lastPos = player.transform.position;
}
void Update()
{
//assign player's position to current position
currentPos = player.transform.position;
//going up
if (lastPos.y < currentPos.y)
{
up = true;
down = false;
equal = false;
}
//going down
else if (lastPos.y > currentPos.y)
{
up = false;
down = true;
equal = false;
}
//same level
else if (lastPos.y == currentPos.y)
{
equal = true;
}
if (down == true && equal == true)
{
particleDust.Play();
}
lastPos = currentPos;
}
You can define the up and down functions to define player's movement with bool.
When the direction down is True and lastPos = currentPos
then it means that he was going down and he stopped because the player hit the ground.
I choose this option without using colliders because it can be versatile and be used on every level without adding new things.
I assume this will work but it need more things, i hope this will get you started.
(If i said something wrong please correct me , it help me improve too, thank you!)
Just thinking of how to detect falls from a specific height, I think this should work just fine in most cases:
private float startingHeight = 0.0f;
private bool grounded = true;
private bool landed = false;
//this is the distance the player needs to fall before dust shows up
private float fallingDist = 5.0f;
private void Start()
{
startingHeight = transform.position.y;
}
private void Update()
{
if(grounded) //set this to false when not colliding with the ground
{
startingHeight = transform.position.y;
}
else if(landed) //set this to true when hitting the ground while grounded is false
{
landed = false;
if((startingHeight - transform.position.y) >= fallingDist)
{
//trigger dust particles or animation
}
}
}

Jump functionality for a 2D Top Down Unity game?

I am struggling to find an efficient way to let my player jump in a 2D Top Down world. I can see a lot of tutorials about platformer views where the camera is oriented at the side of the player, but nothing really working for a top down view like startdew Valley.
I am not using physics, so I move the character on the tilemap using a Couroutine which moves the player to the next position on grid, here it is my Update and DoMove methods:
private void Update()
{
if (!isMoving)
{
input.x = Input.GetAxisRaw("Horizontal");
input.y = Input.GetAxisRaw("Vertical");
if (input.x != 0)
input.y = 0;
if (input != Vector2.zero)
{
animator.SetFloat("Horizontal", input.x);
animator.SetFloat("Vertical", input.y);
var targetPos = transform.position + new Vector3(input.x, input.y, 0f);
// obstacle detection
Vector3Int obstaclesMapTile = obstacles.WorldToCell(targetPos - new Vector3(0, .5f, 0));
if (obstacles.GetTile(obstaclesMapTile) == null)
{
StartCoroutine(DoMove(targetPos));
}
}
animator.SetFloat("Speed", input.sqrMagnitude);
}
}
private IEnumerator DoMove(Vector3 newPos)
{
isMoving = true;
while ((newPos - transform.position).sqrMagnitude > Mathf.Epsilon)
{
transform.position = Vector3.MoveTowards(transform.position, newPos, moveSpeed * Time.fixedDeltaTime);
yield return null;
}
transform.position = newPos;
isMoving = false;
}
Is there anybody which could give me an hint on how to add a jumping feature? ( ideally with animation support?) I am kind of running out of ideas.
Thanks in advance.
Just think of it as animation only. Since it is 2D top down, it's more about it looking like it jumps, and then if it has to go over something while in the jump animation, test for just that.
For example; if over hole and jump animation is playing, then allow movement over the whole, otherwise fall. So if the player presses the button for jump, the animation would play, and there should be some variable storing what animation the player is currently in.

Unity changing friction from code not working (2D)

I want to change a collider's physic's material from code, I use the code below. I see the material's friction changing in the inspector, however the collider behaves as if the friction wouldn't change.
void checkOnGround() {
Transform t;
foreach(Collider2D c in collidingTiles) {
t = c.transform;
if(t.position.y - transform.position.y < -Misc.TILE_SIZE * 0.75f) {
onGround = true;
myCollider.sharedMaterial.friction = 0.8f;
return;
}
}
onGround = false;
myCollider.sharedMaterial.friction = 0f;
return;
}
There are knowed Unity bug.
You can disable/enable your collider to got the material changed applied, and a little flick texture sometimes.

Gun doesn't zoom out

I have a problem with my weapon's zoom script. I have been stuck on this for hours now. I have visited many sites in hope of solving my problem, but to no avail!
I don't think the problem has anything to do with Unity, but with my script instead. The code works perfectly fine when I zoom in (holding right click), but doesn't zoom out when I release right click and the animation has finished playing. It stays zoomed in! Once the animation has ended and I release right click, the weapon stays zoomed in.
The zoomIn() function works fine, but the gun doesn't zoom out during the zoomOut() function. I know the zoomOut() function works fine, because the camera's FOV resets back to what it was(60), but the animation doesn't rewind (maybe because it's stopped?). I have tried changing the animation's time, changing its speed and rewinding and many other things. If I am fully zoomed in and I zoom in again (I right click once the animation has finished playing), the gun jumps back to its original position and plays the zoom animation again.
The script makes perfect sense to me, so I don't know what is going on or how to fix it!
Below is my code:
#pragma strict
var arms : GameObject;
var zoomed : boolean = false;
function Update () {
if (Input.GetMouseButton(1) && zoomed == false) {
zoomIn();
}
if (!Input.GetMouseButton(1)) {
zoomOut();
}
}
function zoomIn() {
if (Input.GetMouseButton(1)) {
animation.Play("zoom");
camera.main.fieldOfView = 50;
arms.active = false;
yield WaitForSeconds(0.3);
zoomed = true;
}
}
function zoomOut() {
zoomed = false;
if (zoomed == false) {
animation.Rewind("zoom");
camera.main.fieldOfView = 60;
arms.active = true;
}
}
Please help
Thanks in advance
You're trying to use Animation.Rewind. This only rewinds the animation, but does not (AFAIK) play the animation in reverse
Try this out instead.
Replace your zoomIn() and zoomOut() methods with the below
function zoomIn() {
//A speed of 1 means that the animation will play at 1x in the positive timeline
animation["zoom"].speed = 1;
//Set the time to the FIRST key frame.
animation["zoom"].time = 0;
animation.Play("zoom");
camera.main.fieldOfView = 50;
arms.active = false;
yield WaitForSeconds(0.3);
zoomed = true;
}
function zoomOut() {
zoomed = false;
//A speed of -1 means that the animation will play the animation at 1x speed in reverse
animation["zoom"].speed = -1;
//Set the time to the LAST key frame. Replace the number "10" with the time of your last keyframe
animation["zoom"].time = 10;
animation.Play("zoom");
camera.main.fieldOfView = 60;
arms.active = true;
}

Make Sprite Draggable When Touched

Is there a way to make a sprite draggable but only when the sprite itself is touched? Currently i have my game ,which uses anengine, set up to where the sprite follows your finger ever time the scene is touched. If you touch the opposite side of the scene the sprite gets "teleported" which is what i dont want.
I tried overriding the onAreaTouched method of the sprite and made it set its coordinates to where your finger currently is but this doesnt work too well. If you make sudden movements the draggablity wears off.
is there any simple way to accomplish this?
Answering my own question... i used this code and it worked perfectly:
draggableSprite = new Sprite(CAM_WIDTH/2, CAM_HEIGHT/2,
spriteTextureRegion, mVertexBufferObjectManager){
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float pTouchAreaLocalX, float pTouchAreaLocalY) {
if(pSceneTouchEvent.isActionMove()){
spriteIsTouched = true;
}
else{
spriteIsTouched = false;
}
return super
.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
}
};
scene.attachChild(draggableSprite);
scene.registerTouchArea(draggableSprite);
scene.setOnSceneTouchListener(new IOnSceneTouchListener() {
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
// TODO Auto-generated method stub
if(spriteIsTouched){
draggableSprite.setPosition(pSceneTouchEvent.getX() - (draggableSprite.getWidth()/2), pSceneTouchEvent.getY() - (draggableSprite.getHeight()/2));
//This sets the position of the sprite and then
//offsets the sprite so its center is at your finger
}
return false;
}
});`