Unity C#: How to make moving character like in Feeding Frenzy? - c#

This game I create that the characters is moving to right only by following the cursor. I want like Feeding Frenzy, when I moving the mouse the characters will follow the cursors and when it press short left click the character have more speed.
The problem in my code is when I press long left click, the character also going faster.
this is my code:
//variable for moving characters
public float moveSpeed;
public float turnSpeed;
private Vector3 moveDirection;
//variable for detect short/long click
private float t0;
private bool longClick;
private bool shortClick;
void Start ()
{
moveDirection = Vector3.right;
t0 = 0f;
longClick = false;
shortClick = false;
}
void Update ()
{
// code to moving my characters (moving to right only)
Vector3 currentPosition = transform.position;
Vector3 moveToward = Camera.main.ScreenToWorldPoint( Input.mousePosition );
moveDirection = moveToward - currentPosition;
moveDirection.z = 0;
moveDirection.Normalize();
if (moveDirection.x <= 0)
{
moveDirection = Vector3.right;
}
Quaternion rot = Quaternion.LookRotation (transform.position - moveToward, Vector3.forward);
rot *= Quaternion.Euler (0, 0, 90);
transform.rotation = rot;
transform.eulerAngles = new Vector3 (0, 0, transform.eulerAngles.z);
Vector3 target = moveDirection * moveSpeed + currentPosition;
transform.position = Vector3.Lerp( currentPosition, target, Time.deltaTime );
float targetAngle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Slerp( transform.rotation,
Quaternion.Euler( 0, 0, targetAngle ),
turnSpeed * Time.deltaTime );
//THIS IS MY PROBLEM!
//IN MY CODE BELOW, WHEN I PRESS LONG CLICK IT HAVE moveSpeed=12.
//I WANT moveSpeed = 12 WHEN I PRESS SHORT CLICK ONLY
if (Input.GetMouseButtonDown (0))
{
t0 = Time.time;
moveSpeed = 12;
}
else if (Input.GetMouseButtonUp(0) && (Time.time - t0) > 0.5f)
{
longClick = true;
moveSpeed = 3;
}
else if (Input.GetMouseButtonUp(0) && (Time.time - t0) < 0.5f)
{
shortClick = true;
moveSpeed = 3;
}
longClick = false;
shortClick = false;
}

function Update()
{
longClick = false; //Remove this
shortClick = false; //Remove this
if ( Input.GetMouseButtonDown (0) )
{
t0 = Time.time ;
longClick = false;
shortClick = false;
}
if ( Input.GetMouseButtonUp(0) (Time.time - t0) < 0.2 )
{
longClick = false;
shortClick = true;
}
if ( Input.GetMouseButtonUp(0) (Time.time - t0) > 0.2 )
{
longClick = true;
shortClick = false;
}
//Process Movement
}
And then use if(longclick) or if(shortClick) to do your speed. When there is a short click, the character moves fast and in the next update, the character goes back to the same speed. If you want the character to continue moving in same speed till it gets the next click, then remove the lines right after update.
process the character movement after the longClick and shortClick is set.

Related

Unity - the player jumps too high when stuck to a wall

I'm writing some code to create a Minecraft Quake like game but I have an issue with the jump mecanic. When I'm stuck to a wall the player jump to high (see the video).
I use a Rigidbody for the physics and I modify that velocity to move the player. There is a Physic Material on the player's Collider with no consideration for friction or bouncing.
If you have ideas to fix the bug or an alternative to work around the problem, I'm interested.
How it looks like
Here is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum PlayerMovementState {
Sneak,
Walk,
Run
}
public class PlayerControls : MonoBehaviour
{
Rigidbody rb;
Vector3 velocity, desiredVelocity;
PlayerMovementState moveState;
float groundDistance;
[SerializeField]
bool forwardAir, backAir, rightAir, leftAir;
[SerializeField]
LayerMask groundLayer;
[SerializeField]
bool onGround;
bool desiredJump;
float jumpHeight = 1.0f;
private void Awake() {
rb = GetComponent<Rigidbody>();
moveState = PlayerMovementState.Walk;
groundDistance = GetComponentInChildren<Collider>().bounds.extents.y;
}
private void Update() {
Vector2 playerInputs = Vector2.ClampMagnitude(
new Vector2(
Input.GetAxis("Horizontal"),
Input.GetAxis("Vertical")
), 1.0f
);
if (Input.GetKey(KeyCode.LeftShift)) moveState = PlayerMovementState.Sneak;
else if (Input.GetKey(KeyCode.LeftControl)) moveState = PlayerMovementState.Run;
else moveState = PlayerMovementState.Walk;
float speed = moveState == PlayerMovementState.Run ? 10f : (
moveState == PlayerMovementState.Sneak ? 2f : 5f
);
RaycastGround();
onGround = !forwardAir && !backAir && !rightAir && !leftAir;
if (Input.GetButtonDown("Jump")) desiredJump = true;
if (moveState == PlayerMovementState.Sneak)
{
if (forwardAir && playerInputs.y > 0) playerInputs.y = 0f;
if (backAir && playerInputs.y < 0) playerInputs.y = 0f;
if (rightAir && playerInputs.x > 0) playerInputs.x = 0f;
if (leftAir && playerInputs.x < 0) playerInputs.x = 0f;
}
desiredVelocity =
(transform.forward * playerInputs.y + transform.right * playerInputs.x) * speed;
}
private void FixedUpdate() {
velocity = rb.velocity;
float acceleration = 10;
velocity.x = Mathf.MoveTowards(velocity.x, desiredVelocity.x, acceleration);
velocity.z = Mathf.MoveTowards(velocity.z, desiredVelocity.z, acceleration);
if (desiredJump && onGround)
{
desiredJump = false;
float jumpSpeed = Mathf.Sqrt(-2f * Physics.gravity.y * jumpHeight);
velocity.y += jumpSpeed;
}
rb.velocity = velocity;
desiredJump = false;
}
void RaycastGround()
{
forwardAir = !(Physics.Raycast(
transform.position + Vector3.forward * 0.1f,
-Vector3.up,
groundDistance + 0.1f,
groundLayer
));
backAir = !(Physics.Raycast(
transform.position - Vector3.forward * 0.1f,
-Vector3.up,
groundDistance + 0.1f,
groundLayer
));
rightAir = !(Physics.Raycast(
transform.position + Vector3.right * 0.1f,
-Vector3.up,
groundDistance + 0.1f,
groundLayer
));
leftAir = !(Physics.Raycast(
transform.position - Vector3.right * 0.1f,
-Vector3.up,
groundDistance + 0.1f,
groundLayer
));
}
}
Very likely the problem is that the script thinks it's still grounded while it is jumping upwards along the wall.
Depending on what feeling you want, either fix the raycasts such that they only trigger when you are standing directly on top of an object, or you check if the y part of your velocity is <= 0 for your onGround variable.
I did not find a solution to my problem but I found a workaround anyway.
By detecting the walls around the player, I prevent him from moving in the direction of the wall which prevents him from being stuck on it and having this bug when he jumps.
(It means that my problem is not resolved and that I am still looking for a solution)
Video
...
float wallDistance;
...
[SerializeField]
bool forwardWall, backWall, rightWall, leftWall;
...
SpherecastWall();
...
if (forwardWall && playerInputs.y > 0) playerInputs.y = 0f;
if (backWall && playerInputs.y < 0) playerInputs.y = 0f;
if (rightWall && playerInputs.x > 0) playerInputs.x = 0f;
if (leftWall && playerInputs.x < 0) playerInputs.x = 0f;
void SpherecastWall() {
forwardWall = (Physics.SphereCast(
new Ray(transform.position, Vector3.forward),
wallDistance,
.2f,
groundLayer
));
backWall = (Physics.SphereCast(
new Ray(transform.position, -Vector3.forward),
wallDistance,
.2f,
groundLayer
));
rightWall = (Physics.SphereCast(
new Ray(transform.position, Vector3.right),
wallDistance,
.2f,
groundLayer
));
leftWall = (Physics.SphereCast(
new Ray(transform.position, -Vector3.right),
wallDistance,
.2f,
groundLayer
));
}
I think that's because the spheres center gets over the corner of the wall. So when you apply a force the sphere will be pushed over it.
Maybe you could replace the sphere collider of your player with a capsule or a square collider.

Unity Rotate Object to Change Direction

I have a fish which is swimming across the screen. When it gets within 10% of the edge of the screen, I want it to turn begin turning around until it has completely reversed and is now swimming in the opposite direction. This should be more gradual like a fish would swim. I don't want it to rotate on its own axis.
I'm not having any luck getting it to turn around. It only turns partially.
Update
Here's the fish
public class FishSwim : MonoBehaviour
{
public enum Direction { LeftToRight, RightToLeft };
public Direction moveDirection;
[SerializeField]
private float speedMin = 0.5f;
[SerializeField]
private float speedMax = 1f;
[SerializeField]
private bool useOnlySpeedMax = false;
private float speed;
[HideInInspector]
public float removeBeyond;
private void Start()
{
var dist = (transform.position - Camera.main.transform.position).z;
if (moveDirection == Direction.RightToLeft)
removeBeyond = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, dist)).x;
else
removeBeyond = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, dist)).x + FindObjectOfType<SkinnedMeshRenderer>().bounds.size.x;
}
private void OnEnable()
{
speed = Random.Range(speedMin, speedMax);
if (useOnlySpeedMax)
{
speed = speedMax;
}
if (moveDirection == Direction.RightToLeft)
{
speed = -speed;
}
}
// Update is called once per frame
void Update()
{
float realSpeed = speed * Time.deltaTime;
transform.position += Vector3.right * realSpeed;
if (moveDirection == Direction.RightToLeft && transform.position.x < -Mathf.Abs(removeBeyond))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), Time.deltaTime * 40f);
moveDirection = Direction.LeftToRight;
}
else if (moveDirection == Direction.LeftToRight && transform.position.x > Mathf.Abs(removeBeyond))
{
}
}
}
I would use Coroutines to do this. Explanation in comments:
bool isTurning = false;
[SerializeField] float turnPeriod = 0.5f; // how long it takes to turn, smaller=faster
private void OnEnable()
{
speed = Random.Range(speedMin, speedMax);
if (useOnlySpeedMax)
{
speed = speedMax;
}
// Get rid of negative speed
}
void Update()
{
float realDistance = speed * Time.deltaTime;
transform.position += transform.right * realDistance;
// Surely there is a better way than calculating
// Mathf.Abs(removeBeyond) every frame... but that is off-topic
if (!isTurning && (
(moveDirection == Direction.RightToLeft
&& transform.position.x < -Mathf.Abs(removeBeyond)
) || (moveDirection == Direction.LeftToRight
&& transform.position.x > Mathf.Abs(removeBeyond)
) ) )
{
// If we aren't already turning and we should be, start turning:
StartCoroutine(Turn());
}
}
IEnumerator Turn()
{
isTurning = true;
Vector3 startForward = transform.forward;
// find end speed and direction
Direction endDirection = moveDirection == Direction.RightToLeft ?
Direction.LeftToRight:Direction.RightToLeft;
// keep track of how much of our turning time has elapsed
float elapsedTimePortion = Time.deltaTime/turnPeriod;
// turn until you've spent enough time turning
while (elapsedTimePortion < 1f)
{
// by whatever portion we've spent time turning, turn starting forward
// 180 degrees around up axis
float angle = 180f * elapsedTimePortion;
Vector3 newForward = Quaternion.AngleAxis(angle, Vector3.up) * startForward;
transform.rotation = Quaternion.LookRotation(newForward);
yield return null;
// next frame - update how long we've been turning
float newElapsedTimePortion = elapsedTimePortion + Time.deltaTime/turnPeriod;
if (newElapsedTimePortion >= 0.5f && elapsedTimePortion < 0.5f)
{
// If we've just passed 50% of the turn,
// make fish move opposite direction
moveDirection = endDirection;
}
elapsedTimePortion = newElapsedTimePortion;
}
// we're done turning, just set the rotation to the end rotation.
isTurning = false;
transform.rotation = Quaternion.LookRotation(-startForward);
// Does removeBeyond need to be updated here? There are a few lines in Start()
// which would suggest that.
}

Rotation smooth in editor but isn't in device

I have a 3D object that I want to rotate with mouse/finger swipe, so I made the script below.
The object's rotation looks smooth on editor, but when playing the game on real device (android), the rotation didn't follow the finger movement immediately, it takes some milliseconds to follow finger, it isn't smooth and the controls become hard and frustrating!
float sensitivity = 0.8f;
Vector2 firstPressPos;
Vector2 secondPressPos;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//save began touch 2d point
firstPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
}
if (Input.GetMouseButton(0))
{
//save ended touch 2d point
secondPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
if (firstPressPos != secondPressPos)
{
float RotX = Input.GetAxis("Mouse X") * sensitivity * Time.deltaTime;
float RotY = Input.GetAxis("Mouse Y") * sensitivity * Time.deltaTime;
transform.RotateAround(Vector3.up, RotX);
transform.RotateAround(Vector3.right, -RotY);
}
}
}
try this code
// Screen Touches
Vector2?[] oldTouchPositions = {
null,
null
};
// Rotation Speed
public float rotSpeed = 0.5f;
public void Update()
{
if (Input.touchCount == 0)
{
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
else if (Input.touchCount == 1)
{
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else
{
Vector2 newTouchPosition = Input.GetTouch(0).position;
float distanceX = (oldTouchPositions[0] - newTouchPosition).Value.x;
float distanceY = (oldTouchPositions[0] - newTouchPosition).Value.y;
float rotX = distanceX * rotSpeed * Mathf.Deg2Rad;
float rotY = distanceY * rotSpeed * Mathf.Deg2Rad;
transform.Rotate(Vector3.up, rotX * 5, Space.Self);
transform.Rotate(Vector3.left, rotY * 5, Space.Self);
oldTouchPositions[0] = newTouchPosition;
}
}
else
{
if (oldTouchPositions[1] == null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = Input.GetTouch(1).position;
}
else
{
}
}
}
Here's a script I found a few years back that manipulates X axis spin with Mouse or Touches. It seems to work well with touches, but not as good with Mouse. Try it and let me know if it behaves a bit better. This one should adjust the spinning speed dynamically:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpinDrag : MonoBehaviour {
float f_lastX = 0.0f;
float f_difX = 0.5f;
float f_steps = 0.0f;
int i_direction = 1;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
f_difX = 0.0f;
}
else if (Input.GetMouseButton(0))
{
f_difX = Mathf.Abs(f_lastX - Input.GetAxis("Mouse X"));
if (f_lastX < Input.GetAxis("Mouse X"))
{
i_direction = -1;
transform.Rotate(Vector3.up, -f_difX);
}
if (f_lastX > Input.GetAxis("Mouse X"))
{
i_direction = 1;
transform.Rotate(Vector3.up, f_difX);
}
f_lastX = -Input.GetAxis("Mouse X");
}
else
{
if (f_difX > 0.5f) f_difX -= 0.05f;
if (f_difX < 0.5f) f_difX += 0.05f;
transform.Rotate(Vector3.up, f_difX * i_direction);
}
}
}

Jumping at an angle with Unity and C#

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.

Wall jumping height decreases with each jump

Solved - I ended up removing playerController.SimpleMove and having playerController.Move control all the player's movement.
So I have been trying to make my character wall jump between to walls. I've been able to make it work however, after each successful wall jump the height of the next jump decreases. This gets to the point where it starts wall jumping downwards. I have no idea why it does this. Before each time pressing the space bar, I am resetting the movement Vector3's to zero and then reapplying the correct values to the jump. I have even gone through the console to look at the vertical changes and neither moveDirection and moveAmount get a large enough value change to make this happen.
Because I am just trying this out, below is all the code that is affecting the player.
public float rotateSpeed = 3.0f;
public float walkSpeed = 5.0f;
public float runSpeed = 15.0f;
public float jumpSpeed = 10.0f;
public float acceleration = .05f;
public bool running = false;
public bool jumping = false;
public bool falling = false;
public bool onWall = false;
public bool wallJumping = false;
public bool stay = false;
private CharacterController playerController;
private Animator playerAnimator;
private float speed;
private Vector3 moveAmount;
private float animationSpeed;
private float currentSpeed;
private float targetSpeed;
private float moveSpeed;
float gravity = 10f;
private Vector3 moveDirection = Vector3.zero;
// Use this for initialization
void Start () {
playerController = GetComponent<CharacterController>();
playerAnimator = GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
transform.Rotate(0, Input.GetAxis("Horizontal") * rotateSpeed, 0);
if (onWall)
{
playerAnimator.SetBool("Wall Holding", true);
jumping = false;
}
else
{
playerAnimator.SetBool("Wall Holding", false);
}
if (stay)
{
moveDirection = Vector3.zero;
moveAmount = Vector3.zero;
}
#region Player Controls
if (Input.GetButton("Vertical") && !wallJumping)
{
moveSpeed = (Input.GetKey(KeyCode.LeftShift)) ? runSpeed : walkSpeed;
moveAmount = transform.TransformDirection(Vector3.forward);
}
else
{
moveSpeed = 0;
moveAmount = Vector3.zero;
}
if (playerController.isGrounded){
moveDirection = Vector3.zero;
jumping = false;
wallJumping = false;
onWall = false;
stay = false;
}
else
{
if (!stay)
onWall = false;
}
if (Input.GetKeyDown(KeyCode.Space))
{
if (playerController.isGrounded)
{
moveDirection.y = jumpSpeed;
jumping = true;
}
else if (onWall)
{
moveDirection = Vector3.zero;
moveAmount = Vector3.zero;
wallJumping = true;
moveDirection += transform.forward * jumpSpeed * 2f;
moveDirection += transform.up * jumpSpeed * 2f;
stay = false;
}
}
if (Input.GetKeyDown(KeyCode.F))
{
if (playerAnimator.GetBool("fight"))
{
playerAnimator.SetBool("fight", false);
}
else
{
playerAnimator.SetBool("fight", true);
}
}
#endregion Player Controls
moveDirection.y -= gravity * Time.deltaTime;
Debug.Log(moveDirection.x);
targetSpeed = Input.GetAxis("Vertical") * moveSpeed;
currentSpeed = SpeedFactor(targetSpeed, currentSpeed, acceleration);
if (currentSpeed > walkSpeed)
running = true;
else
running = false;
playerAnimator.SetFloat("movespeed", currentSpeed);
if (!stay)
{
playerController.SimpleMove(currentSpeed * moveAmount);
playerController.Move(moveDirection * Time.deltaTime);
}
}
private float SpeedFactor (float targetSpeed, float currentSpeed, float dilation) {
if ( currentSpeed < targetSpeed) {
currentSpeed += dilation;
if ( currentSpeed > targetSpeed) {
currentSpeed = targetSpeed;
}
}
else if ( currentSpeed > targetSpeed) {
currentSpeed -= dilation;
if ( currentSpeed < targetSpeed) {
currentSpeed = targetSpeed;
}
}
return currentSpeed;
}
void OnControllerColliderHit (ControllerColliderHit hit) {
if (hit.gameObject.tag == "JumpingWall" && !playerController.isGrounded && !onWall && (jumping || wallJumping))
{
onWall = true;
transform.Rotate(0,180,0);
stay = true;
}
}
The simplest explanation is that transform.forward and/or transform.up vectors begin to diverge from your expectations over time. This would explain how it even seems to be jumping "backwards" eventually when you apply the lines below. Are you sure these vectors are oriented as you expect after the jumper collides with a wall (prior to the next jump)?
moveDirection += transform.forward * jumpSpeed * 2f;
moveDirection += transform.up * jumpSpeed * 2f;

Categories

Resources