How to move the character in a certain way? - unity3d

There is a way. The character starts at the midpoint. Then it should move to the right, if HorizontalAxis > 0 and to the left, if < 0. I have did something like this -
Way:
public Transform[] PatrolPoints;
public Transform Way;
public int CurrentPoint;
public int NeedPoint;
if (transform.position == PatrolPoints[CurrentPoint].position && CurrentPoint < PatrolPoints.Length-1)
{
//PatrolPoints[CurrentPoint];
NeedPoint = CurrentPoint + 1;
}
else if(transform.position == PatrolPoints[NeedPoint].position && CurrentPoint != PatrolPoints.Length - 1)
{
CurrentPoint++;
}
else if(transform.position == PatrolPoints[PatrolPoints.Length - 1].position)
{
NeedPoint--;
}
if (CurrentPoint != PatrolPoints.Length - 1 && moveAxis > 0)
{
transform.position = Vector3.MoveTowards(transform.position, PatrolPoints[NeedPoint].position, moveAxis * moveRate * Time.deltaTime);
//An error occurs here
}
else if(CurrentPoint > 0 && moveAxis < 0)
{
transform.position = Vector3.MoveTowards(transform.position, PatrolPoints[NeedPoint - 1].position, -moveAxis * moveRate * Time.deltaTime);
}
Length of the array - 3 elements.
From the middle point to the right, the character normally goes both left and right, but as soon as I get to the last point, an error occurs -
Array index is out of range
During the error variables are:
NeedPoint: -1;
CurrnetPoint: 2;
And from the middle to the left point the character does not go at all.

this is the solution for:
The character starts at the midpoint. Then it should move to the
right, if HorizontalAxis > 0 and to the left, if < 0.
i assumed that "move to the right" means increasing the index in array and "move to the left" means decreasing the index in array
public Transform[] PatrolPoints;
public int NextPointOnLeft = 0; // because player starts at 1
public int NextPointOnRight = 2; // because player starts at 1
if (HorizontalAxis < 0)
{
if (transform.position == PatrolPoints[NextPointOnLeft].position)
{
if(NextPointOnLeft > 0)
{
--NextPointOnLeft;
}
// EDIT: NextPointOnRight = NextPointOnLeft + 1;
}
// EDIT:
NextPointOnRight = NextPointOnLeft + 1;
transform.position = Vector3.MoveTowards(transform.position, PatrolPoints[NextPointOnLeft].position, moveRate * Time.deltaTime);
}
if (HorizontalAxis > 0)
{
if (transform.position == PatrolPoints[NextPointOnRight].position)
{
if(NextPointOnRight < PatrolPoints.Length-1)
{
++NextPointOnRight;
}
// EDIT: NextPointOnLeft = NextPointOnRight - 1;
}
// EDIT:
NextPointOnLeft = NextPointOnRight - 1;
transform.position = Vector3.MoveTowards(transform.position, PatrolPoints[NextPointOnRight].position, moveRate * Time.deltaTime);
}
if you need a different solution, please specify what you need

Related

How to prevent automatic moving of an object when touched by other object

I have a car in my project, when I hit other objects by it, it goes to it's opposite axis, but when I use cube to hit other objects, it works correctly. Here is the code for moving the car:
// Update is called once per frame
void Update()
{
if (Input.GetButton("Vertical"))
{
VerticalMove = Input.GetAxis("Vertical") * Time.deltaTime * 10;
transform.Translate(0, 0, VerticalMove);
if (Input.GetButton("Horizontal"))
{
if (Input.GetAxis("Vertical") > 0)
{
HorizontalMove = Input.GetAxis("Horizontal") * Time.deltaTime * 50;
transform.Rotate(0, HorizontalMove, 0);
}
else
{
float x = Input.GetAxis("Horizontal");
if (x > 0) {
x -= (x*2);
} else {
x = x * (-2) / 2;
}
HorizontalMove = x * Time.deltaTime * 50;
transform.Rotate(0, HorizontalMove, 0);
}
}
}
and the car is downloaded form asset store named "ARCADE Free Racing Car"

Move Object around a platform of tiles in Unity

I want to make a spinning spike to move around a platform made out of tiles like in the following
I have written every possible state on where to move when platform tiles block the spike's way. It would look something like this
for (int i = 0; i < platformTileMap.Length; i++)
{
if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(0, -1, 0))) // BOTTOM
{
moveX = moveDir;
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(0, 1, 0))) // TOP
{
moveX = -moveDir;
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(-1, -1, 0))) //BOT LEFT
{
if (moveDir == 1)
{
moveY = -1;
}
else moveX = moveDir;
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(1, 1, 0))) //TOP RIGHT
{
if (moveDir == 1)
{
moveY = 1;
}
else moveX = -moveDir;
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(1, -1, 0))) // BOT RIGHT
{
if (moveDir == 1)
{
moveX = moveDir;
}
else
{
moveY = -1;
}
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(-1, 1, 0))) // TOP LEFT
{
if (moveDir == -1)
{
moveY = 1;
}
else
{
moveX = -moveDir;
}
}
I feel like there has to be a more efficient way to solve this. Do I really have to write every possibility in if statements? Can I achieve this with pathfinding?
How about this
Use raycast
Place Empty GameObject and rotate spike when it arrives them
You could create an array of points to move to.
public Vector3[] movePoints;
You can set movePoints in inspector or in code (such as Start function) user choice
In the update loop lerp to the next point in sequence, when arrived pull the next point, unless we are at the end of the array then pull the first point in the array, rinse and repeat forever.
https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
Set this up properly once, when you make more blades and different configurations or want to change speed it will be ez pz.
For anyone interested. Here is how i solved it:
GridLayout platformGridLayout;
Grid platformGrid;
Tilemap[] platformTileMap;
[SerializeField] float rotationSpeed;
[SerializeField] float moveSpeed;
[SerializeField] private LayerMask platformLayerMask;
Vector3Int startPos;
Vector3Int currentCellPosition;
Vector3 raycastPlatformDir;
Vector3 raycastMoveDir;
float platformRaycastDist;
// Start is called before the first frame update
void Start()
{
movePoints = new List<Vector3Int>();
platformGridLayout = transform.parent.GetComponentInParent<GridLayout>();
platformGrid = transform.parent.GetComponentInParent<Grid>();
startPos = platformGridLayout.WorldToCell(transform.position);
Debug.Log("Cell Startposition: " + startPos);
PlatformToMoveOn();
GetStartRaycastDir();
platformRaycastDist = platformGridLayout.cellSize.x;
Debug.Log("CellCenterToWorld of Startposition: " + platformGrid.GetCellCenterWorld(startPos));
Debug.Log(platformGrid.GetCellCenterLocal(currentCellPosition + Vector3Int.FloorToInt(raycastPlatformDir) + Vector3Int.FloorToInt(raycastMoveDir)));
}
private void PlatformToMoveOn()
{
platformTileMap = new Tilemap[2];
platformTileMap[0] = GameObject.Find("Platform").GetComponent<Tilemap>();
platformTileMap[1] = GameObject.Find("MovingPlatform").GetComponent<Tilemap>();
}
private void GetStartRaycastDir()
{
for (int i = 0; i < platformTileMap.Length; i++)
{
if (platformTileMap[i].HasTile(startPos + new Vector3Int(0, -1, 0))) // BOTTOM
{
raycastPlatformDir = Vector3.down;
}
else if (platformTileMap[i].HasTile(startPos + new Vector3Int(0, 1, 0))) // TOP
{
raycastPlatformDir = Vector3.up;
}
else if (platformTileMap[i].HasTile(startPos + new Vector3Int(1, 0, 0))) // RIGHT
{
raycastPlatformDir = Vector3.right;
}
else if (platformTileMap[i].HasTile(startPos + new Vector3Int(-1, 0, 0))) // LEFT
{
raycastPlatformDir = Vector3.left;
}
}
raycastMoveDir = Quaternion.Euler(0, 0, 90) * raycastPlatformDir * Mathf.Sign(moveSpeed);
//raycastMoveDir = new Vector3(raycastPlatformDir.y, raycastPlatformDir.x) * Mathf.Sign(moveSpeed);
}
// Update is called once per frame
void Update()
{
MoveSpike();
}
private void MoveSpike()
{
currentCellPosition = platformGridLayout.WorldToCell(transform.position); // + raycastPlatformDir * platformGridLayout.cellSize.y / 2;
// Debug.Log(cellPosition);
//Debug.Log(raycastMoveDir);
transform.Rotate(0, 0, 300 * rotationSpeed * Time.deltaTime);
RaycastHit2D raycastMove = Physics2D.Raycast(platformGrid.GetCellCenterLocal(currentCellPosition),raycastMoveDir,0.01f,platformLayerMask);
RaycastHit2D raycastPlatform = Physics2D.Raycast(platformGrid.GetCellCenterLocal(currentCellPosition), raycastPlatformDir, platformRaycastDist, platformLayerMask);
Debug.DrawRay(transform.position, raycastMoveDir * 0.01f, Color.red);
Debug.DrawRay(transform.position, raycastPlatformDir * platformRaycastDist, Color.green);
if (currentCellPosition != startPos) { // Check on Platform corners
Debug.Log("Checking");
if (raycastMove.collider != null)
{
// reassign raycastsdirections
RotateRaycastDirections(1);
Debug.Log("Spike Collision");
}
else if (raycastPlatform.collider == null)
{
RotateRaycastDirections(-1);
Debug.Log("Spike on Platform");
}
startPos = currentCellPosition;
}
/*transform.position = Vector3.MoveTowards(transform.position,
platformGrid.GetCellCenterLocal(currentCellPosition + Vector3Int.FloorToInt(raycastPlatformDir) + Vector3Int.FloorToInt(raycastMoveDir)), moveSpeed * Time.deltaTime); */
transform.Translate(raycastMoveDir.x * Mathf.Abs(moveSpeed) * Time.deltaTime, raycastMoveDir.y * Mathf.Abs(moveSpeed) * Time.deltaTime, 0, Space.World);
}
private void RotateRaycastDirections(int angle)
{
raycastPlatformDir = Quaternion.Euler(0, 0, 90) * raycastPlatformDir * angle * Mathf.Sign(moveSpeed);
raycastMoveDir = Quaternion.Euler(0, 0, 90) * raycastMoveDir * angle * Mathf.Sign(moveSpeed);
// raycastPlatformDir = new Vector3(raycastPlatformDir.y, raycastPlatformDir.x) * angle;
//raycastMoveDir = new Vector3(raycastMoveDir.y, raycastMoveDir.x) * -angle;
}
Edit:
This doesnt work on moving Platforms though. Any ideas how i could fix that? I tried changing the raycast position to the tilemapscentercell position but it doesnt work.

Power of trajectory prediction Gold2d

I would like to add a force to my ball in my golf game, so if the player clicks the ball and holds a left mouse button, the power of the shot is growing, so is the trajectory. When the power reaches a maximum value the ball is shot immediately. I have a huge problem with it, and I'm stuck on it for a few days now. Maybe someone can help me? Code below:
internal Rigidbody2D ballRB;
internal Vector3 startPos = Vector3.zero;
int dotCount;
internal bool isClicked = false;
bool trajectoryVisible = false;
bool paraboleReachedEndOfScreen = true;
GameObject trajectoryDots;
GameObject ballClick;
//TrajectoryDots
List<Transform> dots = new List<Transform>();
//shot velocity
Vector2 shotForce = Vector2.zero;
public float startValShootingPower = 3f;
public float shootingPower = 3f;
float minBallPointerDist = 0.5f;
float dotSeparation = 10f;
float dotShift = 5f;
Transform lastDotTransform;
void Start()
{
startPos = transform.position;
startValShootingPower = shootingPower;
ballRB = GetComponent<Rigidbody2D>();
trajectoryDots = GameObject.Find("Trajectory Dots");
ballClick = transform.Find("Ball Click Area").gameObject;
dotCount = trajectoryDots.transform.childCount;
foreach (var dot in trajectoryDots.GetComponentsInChildren<Transform>())
{
dots.Add(dot);
}
dots.Remove(trajectoryDots.transform);
}
void Update()
{
foreach (var dot in dots)
{
if (dot.GetComponent<SpriteRenderer>().enabled)
{
lastDotTransform = dot;
}
}
paraboleReachedEndOfScreen = lastDotTransform.position.x <= -UsefulReferences.CameraViewFrustum.x / 2 || lastDotTransform.position.x >= UsefulReferences.CameraViewFrustum.x / 2;
ballClick.SetActive(!isClicked);
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (Input.GetButtonDown("Fire1"))
{
if (hit.collider != null)
{
//check if the mouse is hovering ball click area
if (hit.collider.transform.root.name == name)
{
trajectoryVisible = true;
}
}
}
if ((Input.GetButtonUp("Fire1") || (paraboleReachedEndOfScreen && Input.GetButton("Fire1"))) && !isClicked && trajectoryVisible) //player released the mouse button or the parabole reached the end of the screen
{
trajectoryVisible = false;
isClicked = true;
UsefulReferences.ballScript.ballRB.constraints = RigidbodyConstraints2D.FreezeRotation;
ballRB.velocity = shotForce;
foreach (var dot in dots)
dot.transform.position = Vector3.zero;
Invoke("GroundCheckAfterShot", 0.1f);
}
if (trajectoryVisible && !isClicked)
{
shotForce = (transform.position - Camera.main.ScreenToWorldPoint(Input.mousePosition)) * shootingPower;
for (int i = 0; i < dotCount; i++)
{
dots[i].gameObject.SetActive(true);
dots[i].transform.position = new Vector2(transform.position.x + shotForce.x * Time.fixedDeltaTime * (dotSeparation * i + dotShift),
transform.position.y + shotForce.y * Time.fixedDeltaTime * (dotSeparation * i + dotShift) - (-Physics2D.gravity.y / 2f * Time.fixedDeltaTime * Time.fixedDeltaTime * (dotSeparation * i + dotShift) * (dotSeparation * i + dotShift)));
}
}
else
{
foreach (var dot in dots)
{
dot.gameObject.SetActive(false);
}
}
//if the ball tried to fly out of the screen
if (transform.position.y > UsefulReferences.CameraViewFrustum.y / 2 || transform.position.x > UsefulReferences.CameraViewFrustum.x / 2 || transform.position.x < -UsefulReferences.CameraViewFrustum.x / 2)
{
OnCollisionEnter2D(null);
}
if (isClicked && UsefulReferences.ballScript.ballRB.constraints == RigidbodyConstraints2D.FreezeAll)
{
UsefulReferences.gcsScript.gameOver = true;
}
}
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Hole")
{
UsefulReferences.gcsScript.Score();
ballRB.constraints = RigidbodyConstraints2D.FreezeAll;
}
}
void OnCollisionEnter2D(Collision2D collision)
{
ballRB.constraints = RigidbodyConstraints2D.FreezeAll;
}
void GroundCheckAfterShot()
{
if (transform.position.y - startPos.y < 0.05f)
ballRB.constraints = RigidbodyConstraints2D.FreezeAll;
}
}

Character unable to dash NorthEast but can dash in other directions, including NorthWest

I'm using the function below on a character controller to Dash in my 2d platformer. For some reason I can dash East, West, North, and NorthWest but not NorthEast, and I can't figure out the issue. I'm sure it's got to be an issue with my math equation used for DashDir but I'm not sure where I went wrong. Facing is simply an Enum holding -1 or 1. Any advice would be helpful - Ideally I'd actually like to be able to dash all 8 directions.
private IEnumerator Dash_Enter () {
dashCooldownTimer = DashCooldown;
Speed = Vector2.zero;
DashDir = Vector2.zero;
Vector2 value = new Vector2(moveX, moveY);
if (value == Vector2.zero) {
value = new Vector2 ((int)Facing, 0f);
} else if (value.x == 0 && value.y > 0 && onGround) {
value = new Vector2 ((int)Facing, value.y);
}
value.Normalize();
Vector2 vector = value * DashSpeed;
Speed = vector;
DashDir = value;
if (DashDir.x != 0f) {
Facing = (Facings)Mathf.Sign (DashDir.x);
}
if (DashDir.y < 0 && onGround) {
DashDir.y = 0;
DashDir.x = Mathf.Sign (DashDir.x);
Speed.y = 0f;
Speed.x *= 2f;
}
yield return new WaitForSeconds (DashTime);
// Wait one extra frame
yield return null;
if (DashDir.y >= 0f) {
Speed = DashDir * EndDashSpeed;
}
if (Speed.y > 0f) {
Speed.y = Speed.y * EndDashUpMult;
}
fsm.ChangeState (States.Normal, StateTransition.Overwrite);
yield break;
}

How to fix this unity 2d sidescroller movement/animation problem

So I am creating my first game in unity and I am currently working on the left to right movement.
I move to the left, let go of the left arrow button -> idle animation.
Press right arrow and character moves to right, let go -> idle.
The problem is I have to wait for the idle animation before I can press to go to the other direction chosen. When I press left and same time right the character does not move.
What I would like to do is fe:
press left -> character goes left, and then
press right at the same time -> character goes right.
So the need to be able to press buttons at the same time, and the last key pressed dictates the movement/animation.
Animation code:
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
this.GetComponent<Animator>().SetInteger("pallotila", 1);
}
if (Input.GetKeyUp(KeyCode.LeftArrow))
{
this.GetComponent<Animator>().SetInteger("pallotila", 0);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
this.GetComponent<Animator>().SetInteger("pallotila", 2);
}
if (Input.GetKeyUp(KeyCode.RightArrow))
{
this.GetComponent<Animator>().SetInteger("pallotila", 0);
}
Player movement code:
if (Input.GetKey(KeyCode.LeftArrow))
{
this.transform.position += Vector3.left * this.nopeus * Time.deltaTime;
this.transform.rotation = this.vasemmalle;
}
if (Input.GetKey(KeyCode.RightArrow))
{
this.transform.position += Vector3.right * this.nopeus * Time.deltaTime;
this.transform.rotation = this.oikealle;
}
Note that you should never use GetComponent in Update better do it once and reuse the reference.
//Here you store the Animator reference
private Animator animator;
private void Awake()
{
animator = GetComponent<Animator>();
}
I'ld also use a switch to define what should happen for which button in order to avoid having the same code over and over again.
private void SetLastPressed(KeyCode code)
{
int value = 0;
switch (code)
{
case KeyCode.None:
value = 0;
break;
case KeyCode.LeftArrow:
value = 1;
break;
case KeyCode.RightArrow:
value = 2;
break;
}
animator.SetInteger("pallotila", value);
lastPressed = code;
}
Simply store and check which button pressed last and make the Input checks exclusive using if-else.
// Here you store the last pressed key
private KeyCode lastPressed = KeyCode.None;
private void Update()
{
if (lastPressed != KeyCode.LeftArrow && Input.GetKeyDown(KeyCode.LeftArrow))
{
SetLastPressed(KeyCode.LeftArrow);
}
else if (lastPressed != KeyCode.RightArrow && Input.GetKeyDown(KeyCode.RightArrow))
{
SetLastPressed(KeyCode.RightArrow);
}
// If none of the keys is pressed reset
else if (lastPressed != KeyCode.None && !Input.GetKey(KeyCode.LeftArrow) && !Input.GetKey(KeyCode.RightArrow))
{
SetLastPressed(KeyCode.None);
}
// And if only one of them is released but the other one still pressed
//go on using that still pressed key again
else if (lastPressed != KeyCode.LeftArrow && Input.GetKeyUp(KeyCode.RightArrow) &&
Input.GetKey(KeyCode.LeftArrow))
{
SetLastPressed(KeyCode.LeftArrow);
}
else if (lastPressed != KeyCode.RightArrow && Input.GetKeyUp(KeyCode.LeftArrow) &&
Input.GetKey(KeyCode.RightArrow))
{
SetLastPressed(KeyCode.RightArrow);
}
For the movement you could simply reuse the lastPresses value than as well
if(lastPressed == KeyCode.LeftArrow)
{
transform.position += Vector3.left * nopeus * Time.deltaTime;
transform.rotation = vasemmalle;
}
else if (lastPressed == KeyCode.RightArrow)
{
transform.position += Vector3.right * nopeus * Time.deltaTime;
transform.rotation = oikealle;
}
Additionally you could/should use a List<KeyCode> to store the last presses. Everytime a button goes down add the button to the end of the list; everytime a button goes up remove it from the list
result => the last pressed button is always the last one in the list.
This makes the return to a previous button way more simple and flexible without adding/changing so much lines of code like
private List<KeyCode> lastPresses = new List<KeyCode>();
private KeyCode lastPressed = KeyCode.None;
private Animator animator;
private void Awake()
{
animator = GetComponent<Animator>();
}
private void SetLastPressed(KeyCode code)
{
int value = 0;
switch (code)
{
case KeyCode.None:
value = 0;
break;
case KeyCode.LeftArrow:
value = 1;
break;
case KeyCode.RightArrow:
value = 2;
break;
}
animator.SetInteger("pallotila", value);
lastPressed = code;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
if (!lastPresses.Contains(KeyCode.LeftArrow)) lastPresses.Add(KeyCode.LeftArrow);
}
else if (Input.GetKeyUp(KeyCode.LeftArrow))
{
if (lastPresses.Contains(KeyCode.LeftArrow)) lastPresses.Remove(KeyCode.LeftArrow);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
if (!lastPresses.Contains(KeyCode.RightArrow)) lastPresses.Add(KeyCode.RightArrow);
}
else if (Input.GetKeyUp(KeyCode.RightArrow))
{
if (lastPresses.Contains(KeyCode.RightArrow)) lastPresses.Remove(KeyCode.RightArrow);
}
var currentCode = lastPresses.Count > 0 ? lastPresses[lastPresses.Count - 1] : KeyCode.None;
if (currentCode != lastPressed) SetLastPressed(currentCode);
if (lastPressed == KeyCode.LeftArrow)
{
transform.position += Vector3.left * nopeus * Time.deltaTime;
transform.rotation = vasemmalle;
}
else if (lastPressed == KeyCode.RightArrow)
{
transform.position += Vector3.right * nopeus * Time.deltaTime;
transform.rotation = oikealle;
}
}
You can change the "Value" Variable to
animator.SetInteger("pallotila", 0);
break;
in the location of
value = 0;
break;
or change
int value;
to
int value = 0;
in the code by #derHugo