Change texture on key down - c#

Here it is my method to get keyboard state and change texture based on which key is pressed.
private void CheckKeyboardAndUpdateMovement()
{
KeyboardState keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyUp(Keys.Left)) { ChangeTexture(1); }
if (keyboardState.IsKeyUp(Keys.Right)) { ChangeTexture(2); }
if (keyboardState.IsKeyDown(Keys.Left))
{
Movement -= Vector2.UnitX;
ChangeTexture(3);
}
if (keyboardState.IsKeyDown(Keys.Right))
{
Movement += Vector2.UnitX;
ChangeTexture(4);
}
if ((keyboardState.IsKeyDown(Keys.Space) || keyboardState.IsKeyDown(Keys.Up)) && IsOnFirmGround())
{
Movement = -Vector2.UnitY * JumpHeight;
}
}
It works if direction are pressed, but doesn't make its own job when nothing is pressed (just because both the IsKeyUp are true). Only the cases' order prevents the static texture to be shown while moving the sprite...
My question is, how can I make a clean solution of this problem? I already have an idea, but I don't like it at all...

If you want another solution, but is still similar to yours.
enum Direction { Left = 1, Right = 2}
Direction dir = Direction.Left; //or whatever
private void CheckKeyboardAndUpdateMovement()
{
KeyboardState keyboardState = Keyboard.GetState();
ChangeTexture((int)dir);
if (keyboardState.IsKeyDown(Keys.Left))
{
Movement -= Vector2.UnitX;
ChangeTexture(3);
dir = Direction.Left;
}
if (keyboardState.IsKeyDown(Keys.Right))
{
Movement += Vector2.UnitX;
ChangeTexture(4);
dir = Direction.Right;
}
if ((keyboardState.IsKeyDown(Keys.Space) || keyboardState.IsKeyDown(Keys.Up)) && IsOnFirmGround())
{
Movement = -Vector2.UnitY * JumpHeight;
}
}
You can do something similar with walking sprites.

The worst solution I thought on, it's to store the sprite direction when the last key has been pressed and make a check on the next update, but it will become a mess more the keys and textures I'll have to control...
// Having a "bool leftDirectionOnLastMovement;" (worst name ever seen)
private void CheckKeyboardAndUpdateMovement()
{
KeyboardState keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyUp(Keys.Left) && leftDirectionOnLastMovement)
ChangeTexture(1);
if (keyboardState.IsKeyUp(Keys.Right) && !leftDirectionOnLastMovement)
ChangeTexture(2);
if (keyboardState.IsKeyDown(Keys.Left))
{
Movement -= Vector2.UnitX;
ChangeTexture(3);
leftDirectionOnLastMovement = true;
}
}
if (keyboardState.IsKeyDown(Keys.Right))
{
Movement += Vector2.UnitX;
ChangeTexture(4);
leftDirectionOnLastMovement = false;
}
}
if ((keyboardState.IsKeyDown(Keys.Space) || keyboardState.IsKeyDown(Keys.Up)) && IsOnFirmGround())
{
Movement = -Vector2.UnitY * JumpHeight;
}
}
I really hope someone will suggest me a better way to do this...

Related

OverlapBox sometimes not working as expected, Unity 2d

I am using an overlap box to detect whether an arrow hits the ground or an enemy, the arrow hitting the enemy works, it's that often the arrow will just pass through the ground, not sure if I am missing something.
Heres my code for detecting the ground or enemy.
private void FixedUpdate()
{
damageHit = Physics2D.OverlapBox(damagePosition.position, damageSize, whatIsEnemy);
groundHit = Physics2D.OverlapBox(damagePosition.position, damageSize, whatIsGround);
if (!hasHitGround)
{
if (damageHit)
{
Collider2D[] detectedObjects = Physics2D.OverlapBoxAll(damagePosition.position, damageSize, whatIsEnemy);
foreach (Collider2D collider in detectedObjects)
{
IDamageable damageable = collider.GetComponent<IDamageable>();
if (damageable != null)
{
damageable.Damage(weaponData.attackDamage);
Destroy(gameObject);
}
IKnockbackable knockbackable = collider.GetComponent<IKnockbackable>();
if (knockbackable != null)
{
knockbackable.KnockBack(weaponData.knockbackAngle, weaponData.knockbackStrength, (int)Mathf.Sign(transform.rotation.y));
}
}
}
if (groundHit)
{
rb.gravityScale = 0f;
rb.velocity = Vector2.zero;
hasHitGround = true;
Destroy(gameObject, 10f);
}
else if (Mathf.Abs(xStartPos - transform.position.x) >= travelDistance && !isGravityOn)
{
isGravityOn = true;
rb.gravityScale = gravity;
}
}
}
private void OnDrawGizmos()
{
Gizmos.DrawWireCube(damagePosition.position, damageSize) ;
}
I thought that the hitbox may have been to small and it would just pass through wall due to not hitting it on any frame. After making the hitbox larger it still did not help, here you can see that even though the overlap box is overlaping the collider the arrow will continue on.

How to fix movement with swipe to right and left?

I lost a lot of time trying to find what is the problem in code but I can not find the solution why my code is not triggered.
In my previous game when I implemented this code it worked perfectly, now when i implement into new game this same code for touch movement it doesn't work.
I tried to debug the code and put Debug.Log into Update method and when i swipe over screen it doesn't even get trigger.
This is the code:
int left = 0;
int right = 0;
int maxLeftCycles = 5;
int maxRightCycles = 5;
void Start()
{
//touch
left = maxLeftCycles;
right = maxRightCycles;
}
private void Update()
{
timer += Time.deltaTime;
if (Input.GetKeyUp(KeyCode.RightArrow) ||
Swipe.swipe == Swipe.SwipeDirection.right)
{
Swipe.ResetSwipe();
right = 0;
}
if (Input.GetKeyUp(KeyCode.LeftArrow) ||
Swipe.swipe == Swipe.SwipeDirection.left)
{
Swipe.ResetSwipe();
left = 0;
}
}
void FixedUpdate()
{
if (left < maxLeftCycles && !isMoving)
{
desiredPos = transform.position + Vector3.left * 1.52f;
isMoving = true;
left++;
}
if (right < maxRightCycles && !isMoving)
{
desiredPos = transform.position - Vector3.right * 1.52f;
isMoving = true;
right++;
}
if (isMoving)
{
transform.position = Vector3.MoveTowards(transform.position, desiredPos, moveSpeed * Time.deltaTime);
// this == is true if the difference between both
// vectors is smaller than 0.00001
if (transform.position == desiredPos)
{
isMoving = false;
transform.position = desiredPos;
}
}
}
I put Debug.Log in this code and in vector3.right and left but it never get triggered.
if (Input.GetKeyUp(KeyCode.RightArrow) ||
Swipe.swipe == Swipe.SwipeDirection.right)
{
Debug.Log("This is traacked");
Swipe.ResetSwipe();
right = 0;
}
if (Input.GetKeyUp(KeyCode.LeftArrow) ||
Swipe.swipe == Swipe.SwipeDirection.left)
{
Debug.Log("This is traacked");
Swipe.ResetSwipe();
left = 0;
}
This is the code for Swipe script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Swipe : MonoBehaviour
{
private float fingerStartTime = 0.0f;
private Vector2 fingerStartPos = Vector2.zero;
private bool isSwipe = false;
private float minSwipeDist = 50.0f;
private float maxSwipeTime = 0.5f;
public enum SwipeDirection
{
none,
up,
down,
right,
left
}
public static SwipeDirection swipe;
void Start()
{
swipe = SwipeDirection.none;
}
public static void ResetSwipe()
{
swipe = SwipeDirection.none;
}
// Update is called once per frame
void Update()
{
if (Input.touchCount > 0)
{
foreach (Touch touch in Input.touches)
{
switch (touch.phase)
{
case TouchPhase.Began:
/* this is a new touch */
isSwipe = true;
fingerStartTime = Time.time;
fingerStartPos = touch.position;
break;
case TouchPhase.Canceled:
/* The touch is being canceled */
isSwipe = false;
break;
case TouchPhase.Ended:
float gestureTime = Time.time - fingerStartTime;
float gestureDist = (touch.position - fingerStartPos).magnitude;
if (isSwipe && gestureTime < maxSwipeTime && gestureDist > minSwipeDist)
{
Vector2 direction = touch.position - fingerStartPos;
Vector2 swipeType = Vector2.zero;
if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
{
// the swipe is horizontal:
swipeType = Vector2.right * Mathf.Sign(direction.x);
}
else
{
// the swipe is vertical:
swipeType = Vector2.up * Mathf.Sign(direction.y);
}
if (swipeType.x != 0.0f)
{
if (swipeType.x > 0.0f)
{
// MOVE RIGHT
swipe = SwipeDirection.right;
}
else
{
// MOVE LEFT
swipe = SwipeDirection.left;
}
}
if (swipeType.y != 0.0f)
{
if (swipeType.y > 0.0f)
{
// MOVE UP
swipe = SwipeDirection.up;
}
else
{
// MOVE DOWN
swipe = SwipeDirection.down;
}
}
}
break;
}
}
}
}
}
The code in Update method for swipe input which I debug never get called or never work for me.I can not understand what i am doing wrong because the same code actually works in my previous game.
Thank you so much for reading my question I hope there will be some guy who can help me to solve this issue.
If it worked as is before hand in another project I would make sure that you are attaching the script to a game object. If it is attached to a game object make sure that it is not marked as inactive and that you aren't turning the object to inactive somewhere else in your scripts.
If neither of these are the case I would also try removing the script from the object and then reattaching it, and if that still doesn't work try deleting the object the script is attached to (if possible) and then recreate it and reattach the script.

Jump height in relation to timeheld of spacebar

This has been asked before, but none of the answers solved my problem because the problem was always slightly different.
I have a character that jumps on spacebar down. I want it to make higher jumps when the spacebar is pressed longer, with a maximum of twice the normal jump height.
Here's what I came up with so far:
void FixedUpdate () {
if (Input.GetKeyDown(KeyCode.Space) && myRB.velocity.y == 0)
{
timeHeld = 1;
}
if (Input.GetKey(KeyCode.Space) && myRB.velocity.y == 0)
{
myRB.AddForce(Vector3.up * 20,ForceMode2D.Impulse);
timeHeld += Time.deltaTime;
myRB.mass = myRB.mass - timeHeld/10;
}
if (Input.GetKeyUp(KeyCode.Space))
{
myRB.mass = 1;
}
}
Since the jump has to happen on keydown (not keyup), I can't increase the force added on jump, because the force is already applied on keydown. Therefore, I was thinking of lowering the mass of my rigidbody.
The above code "works" if I keep holding spacebar: the character jumps (minimum height), lands, jumps again but now a bit higher, etc. But that's not what I'm looking for, obviously.
This can easily be done by making a Time frame in which Jumping occurs;
Within this time frame u allow upward forces to be applied by holding space bar down. As soon as you reach either the end of the time frame or the end of the button press; you restrict upward velocity until the character has landed.
Let gravity take its own course after you end the jump.
As for the coding part i suggest you start a co routine when the jump happens.
here is some code to u help you get started;
IEnumerator Jumper()
{
if (maxjumpduration!=jumpduration)
{
jumpduration = jumpduration + 0.1f;
yield return new WaitForSeconds(0.1f);
}
else
{
jumpduration = 0;
StopCoroutine(Jumper());
}
}
As for the fact you want have a regular jump as well; make another time frame in which is decided if the press of space bar is considered either a regular jump or a controlled jump; During that initial time frame in which you are still deciding what kind of jump it is; you execute a short part of the jump until you reach a conclusion and then you send it to the correct method.
I added Some ground work for u but try to finish the code yourself;
{
private bool shortjump = false;
private bool checkphase = false;
private bool hitground = false;
private Rigidbody player = new Rigidbody();
private bool jumping = false;
Vector3 sharedjumpforce = new Vector3();
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Initialjump();
}
if (Input.GetKeyUp(KeyCode.Space))
{
if (jumping)
{
shortjump = true;
}
}
if (jumping)
{
if (hitground)
{
jumping = false;
}
}
}
void Initialjump()
{
if (jumping = false)
{
checkphase = true;
jumping = true;
player.AddForce(sharedjumpforce);
Invoke("Standardorcontrolledjump", 0.2f);
}
}
void Standardorcontrolledjump()
{
checkphase = false;
if (shortjump)
{
}
else
{
}
}
}
I don't understand why are you putting
&& myRB.velocity.y == 0
You want it to reduce its mass while in air don't you. Assuming that reducing the mass after the initial force has been applied does allow the Rigidbody to go higher, (force of gravity weakens, im not sure if that happens in Unity)
Why don't you try this
void FixedUpdate () {
// apply force the instant button is pressed. That is only once
if (Input.GetKeyDown(KeyCode.Space) && myRB.velocity.y == 0)
{
myRB.AddForce(Vector3.up * 20,ForceMode2D.Impulse);
timeHeld = 1;
}
// keep subtracting from mass while its held
if (Input.GetKey(KeyCode.Space))
{
timeHeld += Time.deltaTime;
myRB.mass = myRB.mass - timeHeld/10;
}
if (Input.GetKeyUp(KeyCode.Space))
{
myRB.mass = 1;
}
}

Making my XNA sprite jump properly

I have been having great trouble getting my sprite to jump. So far I have a section of code which with a single tap of "W" will send the sprite in a constant velocity upwards. I need to be able to make my sprite come back down to the ground a certain time or height after begining the jump. There is also a constant pull of velocity 2 on the sprite to simulate some kind of gravity.
// Walking = true when there is collision detected between the sprite and ground
if (Walking == true)
if (keystate.IsKeyDown(Keys.W))
{
Jumping = true;
}
if (Jumping == true)
{
spritePosition.Y -= 10;
}
Any ideas and help would be appreciated but I'd prefer a modified version of my code posted if at all possible.
You need to apply an impulse to your sprite as opposed to a constant velocity of 10 like you are doing.
There is a good tutorial here for what you are trying to do.
public class Player
{
private Vector2 Velocity, Position;
private bool is_jumping;
private const float LandPosition = 500f;
public Player(Vector2 Position)
{
this.Position = new Vector2(Position.X, LandPosition);
Velocity = Vector2.Zero;
is_jumping = false;
}
public void UpdatePlayer(Gametime gametime, KeyboardState keystate, KeyboardState previousKeyBoardState)
{
if (!is_jumping)
if (keystate.isKeyDown(Keys.Space) && previousKeyBoardState.isKeyUp(Keys.Space))
do_jump(10f);
else
{
Velocity.Y++;
if (Position.Y >= LandPosition)
is_jumping = false;
}
Position += Velocity;
}
private void do_jump(float speed)
{
is_jumping = true;
Velocity = new Vector2(Velocity.X, -speed);
}
}
fun little mix of psuedocode and some real code, just add the variables that I didn't include at the top.
Also check out Stack Overflow Physics ;) Good luck with your game.
edit: that should be complete, let me know how things go.
I would do something like this...
const float jumpHeight = 60F; //arbitrary jump height, change this as needed
const float jumpHeightChangePerFrame = 10F; //again, change this as desired
const float gravity = 2F;
float jumpCeiling;
bool jumping = false;
if (Walking == true)
{
if (keystate.IsKeyDown(Keys.W))
{
jumping = true;
jumpCeiling = (spritePosition - jumpHeight);
}
}
if (jumping == true)
{
spritePosition -= jumpHeightChangePerFrame;
}
//constant gravity of 2 when in the air
if (Walking == false)
{
spritePosition += gravity;
}
if (spritePosition < jumpCeiling)
{
spritePosition = jumpCeiling; //we don't want the jump to go any further than the maximum jump height
jumping = false; //once they have reached the jump height we want to stop them going up and let gravity take over
}

XNA 3.1 Movement Collision Issue

So heres my problem. I have a box that I want my character to move around. But I want to be able to move around it while holding multiple move commands, for instance..
when moving right (towards the left of the obstacle) I want to be able to hold move right and up or down at the same time without the character sticking to the box. The funny part is, it works fine for the left and right side of the obstacle, yet it sticks when i try it on the top and bottom side of the obstacle.
Heres the Player Class (object im moving)
<!-- language: c# -->
public class Player
{
public Texture2D texture;
public Vector2 position;
public int speed;
public Vector2 offset;
public bool left, right, up, down;
public Rectangle collisionRect
{
get
{
return new Rectangle((int)position.X , (int)position.Y, texture.Width, texture.Height);
}
}
public Vector2 direction;
public Player(Texture2D texture, Vector2 position, int speed)
{
this.texture = texture;
this.position = position;
this.speed = speed;
offset.X = speed;
offset.Y = speed;
left = false;
right = false;
up = false;
down = false;
}
public virtual void Update(GameTime gameTime, Rectangle clientBounds)
{
direction = Vector2.Zero;
if (Keyboard.GetState().IsKeyDown(Keys.A))
{
direction.X -= 1;
left = true;
}
else
left = false;
if (Keyboard.GetState().IsKeyDown(Keys.D))
{
direction.X += 1;
right = true;
}
else
right = false;
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
direction.Y -= 1;
up = true;
}
else
up = false;
if (Keyboard.GetState().IsKeyDown(Keys.S))
{
direction.Y += 1;
down = true;
}
else
down = false;
position += (direction * speed);
}
public virtual void Draw(GameTime gameTime, SpriteBatch spritebatch)
{
spritebatch.Draw(texture, collisionRect, Color.White);
}
}
Heres the Update Method in my maingame
<!-- language: c# -->
public override void Update(GameTime gameTime)
{
// TODO: Add your update code here
player.Update(gameTime, Game.Window.ClientBounds);
if (player.right && HitWall(player))
{
player.position.X -= player.offset.X;
}
else if (player.left && HitWall(player))
{
player.position.X += player.offset.X;
}
if (player.down && HitWall(player))
{
player.position.Y -= player.offset.Y;
}
else if (player.up && HitWall(player))
{
player.position.Y += player.offset.Y;
}
base.Update(gameTime);
}
And the HitWall function
<!-- language: c# -->
public bool HitWall(Player player)
{
for (int i = player.collisionRect.Top; i < player.collisionRect.Bottom; i++)
for (int j = player.collisionRect.Left; j < player.collisionRect.Right; j++)
if (TextureData[i * gameMap.map.Width + j] != Color.White)
return true;
return false;
}
I'm not sure where offset is defined, but I'm assuming it's the movement you've just made that frame.
Your problem is that because you check left & right before up and down, if you're moving diagonally down onto the top edge of the box, then you'll register a hit in the Y direction — HitWall doesn't check which direction you're going, it just checks for a collision. Therefore, the collision in the Y axis stil counts on the line if (player.right && HitWall(player)) and stops your lateral movement.
Best bet is to apply your sideways movement, check for a hit, move back if there is one — then apply your downwards movement, check for a hit, and move back if there is one. Correcting the position like this should mean you slide along the sides as you want.

Categories