So I've been making a small game to do with Snake, and I'm struggling as to how I can make the Snake's Body appear and follow the position of the head whenever the snake's head touches the apple. I've managed to get the Snake's body to spawn but I can't get it to follow the head correctly. Can anyone help me and tell me how I can do this? Thanks!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Snake_Move : MonoBehaviour
{
// variables
public Vector2 pos;
private Vector2 moveDirection;
private float moveTimer;
private float timerSeconds;
//Function which runs once when the program starts
void Start()
{
timerSeconds = 0.0167f;
moveTimer = timerSeconds;
moveDirection = new Vector2(0.1f, 0);
}
//Function which updates itself based on your refresh rate
public void Update()
{
AutoMove();
ChangeDirection();
transform.position = new Vector2(pos.x, pos.y);
transform.eulerAngles = new Vector3(0, 0, AngleCalculator(moveDirection) - 90);
}
//Moves the snake 60 units each second
private void AutoMove()
{
moveTimer += Time.deltaTime;
if (moveTimer > timerSeconds)
{
pos += moveDirection;
moveTimer -= timerSeconds;
}
}
//Changes direction of the snake based on arrow key pressed
private void ChangeDirection()
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
if (moveDirection.y != -0.1f)
{
moveDirection.x = 0;
moveDirection.y = 0.1f;
}
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
if (moveDirection.y != 0.1f)
{
moveDirection.x = 0;
moveDirection.y = -0.1f;
}
}
else if (Input.GetKeyDown(KeyCode.RightArrow))
{
if (moveDirection.x != -0.1f)
{
moveDirection.y = 0;
moveDirection.x = 0.1f;
}
}
else if (Input.GetKeyDown(KeyCode.LeftArrow))
{
if (moveDirection.x != 0.1f)
{
moveDirection.y = 0;
moveDirection.x = -0.1f;
}
}
}
//Calculates the angle at which the snake is moving; used to calculate rotation of sprite
private float AngleCalculator(Vector2 direction)
{
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
return angle;
}
private void SnakeBodySprite()
{
GameObject snakeApple = GameObject.Find("SnakeApple");
Apple_RandomSpawn appleScript = snakeApple.GetComponent<Apple_RandomSpawn>();
//something here?????
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Apple_RandomSpawn : MonoBehaviour
{
private Vector2 foodPos;
void Start()
{
SpawnApple();
}
void Update()
{
transform.position = new Vector2(foodPos.x, foodPos.y);
SnakeAte();
}
public void SpawnApple()
{
foodPos = new Vector2(Random.Range(-17, 17), Random.Range(-9, 9));
}
public void SnakeAte()
{
GameObject snakeBody = GameObject.Find("SnakeBody");
GameObject snakeHead = GameObject.Find("SnakeHead");
Snake_Move snakeMove = snakeHead.GetComponent<Snake_Move>();
if (foodPos.x <= snakeMove.pos.x + 1 &&
foodPos.x >= snakeMove.pos.x - 1 &&
foodPos.y <= snakeMove.pos.y + 1 &&
foodPos.y >= snakeMove.pos.y -1)
{
SpawnApple();
Instantiate(snakeBody);
}
}
}
This is kind of a broad question, so it's hard to answer completely. The thought that comes to my mind is using a Queue of move Vectors for the head, and then applying those movements to the body. You would need a reference to the snake body object, and need to know how many movements the head is from the body. It looks like that might be 60 in your case.
I would add the Queue in this section:
Queue<Vector2> moveDirections = new Queue<Vector2>();
SnakeBody snakeBody; // Reference to 1st snake body element
float offset = 60; // ?
private void AutoMove()
{
moveTimer += Time.deltaTime;
// enqueue the most recent moveDirection
moveDirections.Enqueue(moveDirection);
if (moveTimer > timerSeconds)
{
pos += moveDirection;
moveTimer -= timerSeconds;
// Get oldest moveDirection from the head to apply to the body
Vector2 bodyMovement = moveDirections.Dequeue();
snakeBody.transform.Translate(bodyMovement);
}
// If the queue count is greater than how far ahead the head should be from the
// first body element, remove one from queue.
if (moveDirections.Count > offset) {
moveDirections.Dequeue();
}
}
This would only work for the first body element, so you could add a script to each body element keeping track of its child body element. Position the child element with the same logic used above.
NOTE: I haven't tested this, I'm just trying to give a high-level overview of how to solve this problem.
Related
I am trying to make a grappling hook more fluent but as of right now it is very choppy and does not have the right feel. It currently makes a line and pulls the player there. I have not tried anything yet because I am not even sure we're to start on fixing this. Here is all the grappling code below. `using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(SFPSC_PlayerMovement))] // PlayerMovement also requires Rigidbody
public class SFPSC_GrapplingHook : MonoBehaviour
{
public bool IsGrappling
{
get { return isGrappling; }
}
private SFPSC_PlayerMovement pm;
private Rigidbody rb;
private int segments;
private void Start()
{
segments = rope.segments;
pm = this.GetComponent<SFPSC_PlayerMovement>();
rb = this.GetComponent<Rigidbody>();
}
private bool isGrappling = false;
private void Update()
{
if (crossHairSpinningPart != null)
{
// we need 2 raycasts bc w/ 1 you can grapple through colliders which isn't good
if (Physics.Raycast(SFPSC_FPSCamera.cam.transform.position, SFPSC_FPSCamera.cam.transform.forward, out hitInfo, maxGrappleDistance, layerMask))
{
hitName = hitInfo.collider.name;
if (Physics.Raycast(SFPSC_FPSCamera.cam.transform.position, SFPSC_FPSCamera.cam.transform.forward, out hitInfo, maxGrappleDistance))
{
if (hitName != hitInfo.collider.name)
goto _else;
crossHairSpinningPart.gameObject.SetActive(true);
crossHairSpinningPart.Rotate(Vector3.forward * crossHairSpinSpeed * Time.deltaTime);
goto _out;
}
}
_else:
crossHairSpinningPart.gameObject.SetActive(false);
}
_out:
if (!isGrappling)
{
if (Input.GetKeyDown(SFPSC_KeyManager.Grapple))
Grapple();
return;
}
else
{
if (!Input.GetKey(SFPSC_KeyManager.Grapple))
UnGrapple();
GrappleUpdate();
return;
}
}
[Header("Properties")]
public float maxGrappleDistance = 100.0f;
public SFPSC_Rope rope;
public float maximumSpeed = 100.0f;
public float deceleration = 2500.0f; // This is how much the player is going to decelerate after stopped grappling
public float deceleratingTime = 1.4f; // This is the time the decelerating is going to act on the player after stopped grappling
public RectTransform crossHairSpinningPart;
public float crossHairSpinSpeed = 200.0f;
public float distanceToStop = 2.0f;
public LayerMask layerMask;
public float grappleCooldown = 1.0f;
private bool isBlocked = false;
private Transform location; // the grappled location
private RaycastHit hitInfo;
private string hitName;
public void Grapple()
{
if (isBlocked)
return;
// we need 2 raycasts bc w/ 1 you can grapple through colliders which isn't good
if (Physics.Raycast(SFPSC_FPSCamera.cam.transform.position, SFPSC_FPSCamera.cam.transform.forward, out hitInfo, maxGrappleDistance, layerMask))
{
hitName = hitInfo.collider.name;
if (Physics.Raycast(SFPSC_FPSCamera.cam.transform.position, SFPSC_FPSCamera.cam.transform.forward, out hitInfo, maxGrappleDistance))
{
if (hitName != hitInfo.collider.name)
return;
// We create a GameObject and we parent it to the grappled object.
// If we don't parent it to the object and the object moves the player is stuck only on one location instead of the moving object.
location = new GameObject().transform;//Instantiate(new GameObject(), hitInfo.point, Quaternion.identity).transform;
location.position = hitInfo.point;
location.parent = hitInfo.collider.transform;
if (decelerateTimer != 0.0f)
StopCoroutine(Decelerate());
pm.DisableMovement();
// Rope attaching
rope.segments = (int)((hitInfo.distance / maxGrappleDistance) * segments);
rope.Grapple(transform.position, hitInfo.point);
rb.useGravity = false;
isGrappling = true;
}
}
}
private Vector3 grappleForce;
public void UnGrapple()
{
if (!isGrappling)
return;
if (location != null)
Destroy(location.gameObject);
if (decelerateTimer == 0.0f)
StartCoroutine(Decelerate());
else
decelerateTimer = 0.0f;
pm.EnableMovement();
// Rope detaching
rope.UnGrapple();
Invoke("UnblockGrapple", grappleCooldown);
rb.useGravity = true;
isGrappling = false;
}
private void UnblockGrapple()
{
isBlocked = false;
}
private float decelerateTimer = 0.0f, max;
private IEnumerator Decelerate()
{
WaitForEndOfFrame wfeof = new WaitForEndOfFrame();
max = deceleratingTime * Mathf.Clamp01(targetDistance / 10.0f) * Mathf.Clamp01(rb.velocity.magnitude / 30.0f);
for (; decelerateTimer < max; decelerateTimer += Time.deltaTime)
{
rb.AddForce(-rb.velocity.normalized * deceleration * (1.0f - decelerateTimer / max) * Mathf.Clamp01(rb.velocity.sqrMagnitude / 400.0f) * Time.deltaTime, ForceMode.Acceleration);
yield return wfeof;
}
decelerateTimer = 0.0f;
}
private Vector3 dir;
private float speed = 0.0f, targetDistance;
private void GrappleUpdate()
{
if (location == null)
return;
targetDistance = Vector3.Distance(transform.position, location.position);
rope.segments = (int)((targetDistance / maxGrappleDistance) * segments);
dir = (location.position - transform.position).normalized;
rb.velocity = Vector3.Lerp(rb.velocity, dir * maximumSpeed * Mathf.Clamp01(targetDistance / (4.0f * distanceToStop)), Time.deltaTime);
// Rope updating
rope.UpdateStart(transform.position);
rope.UpdateGrapple();
}
private Vector3 ClampMag(Vector3 vec, float maxMag)
{
if (vec.sqrMagnitude > maxMag * maxMag)
vec = vec.normalized * maxMag;
return vec;
}
}
`
Try using FixedUpdate instead of Update for physics based work (basically all of your code in Update right now). Update is dependent on your computer's clock speed and refresh rate (more or less), and gets called at fairly irregular intervals, because the next update is called in the next frame, after the present frame has finished processing. FixedUpdate makes it frame-rate independent.
Also, you can cap your framerate using Application.targetFrameRate and cap it to a decent FPS.
You could also multiply your movement with Time.deltaTime for smoother movement, although this is a standard practice and yet debatable for use as a smoothing value.
I have created a twin stick movement system for mobile. I have a character moving under the influence of one joystick correctly. The other joystick, the design I want is:
When the shoot JS is moved, look in that direction.
When the shoot JS is released, shoot in the last aimed direction.
What's happening is, the character shoots continuously when the game starts and if I move the ShootJS, the character spins in circles. I'm completely flummoxed as to why this is happening.
Here is my code. Thanks in advance to anybody for any help you provide.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AI;
using Ludiq;
using Bolt;
public class PlayerJSControlSc : MonoBehaviour
{
public GameObject player;
public NavMeshAgent nav;
public Text stateText;
public float moveSpeed;
public Animator animator;
public FloatingJoystick moveJS;
public FloatingJoystick shootJS;
public float rotationSpeed = 10;
public int ammo;
public int mag;
public Transform shotSpawn;
public GameObject bullet;
public float reloadTime;
public Text ammoCount;
[HideInInspector]
int currentMag;
// Start is called before the first frame update
void Start()
{
stateText.text = "";
nav = player.GetComponent<NavMeshAgent>();
animator = player.GetComponent<Animator>();
moveJS = GameObject.Find("Floating JS_Move").GetComponent<FloatingJoystick>();
shootJS = GameObject.Find("Floating JS_Shoot").GetComponent<FloatingJoystick>();
}
// Update is called once per frame
void Update()
{
movePlayer();
playerShoot();
ammoCount.text = currentMag+ "/" + ammo;
}
public void movePlayer()
{
//float x = Input.GetAxis("Horizontal");
//float y = Input.GetAxis("Vertical");
float x = moveJS.Horizontal;
float y = moveJS.Vertical;
nav.velocity = new Vector3(x * moveSpeed, 0, y * moveSpeed);
if (nav.velocity.x != 0 || nav.velocity.z != 0)
{ animator.SetBool("isRunning", true); }
else { animator.SetBool("isRunning", false); }
}
public void playerShoot()
{
bool isAiming = false;
float x = shootJS.Horizontal; float z = shootJS.Vertical;
if (x != 0 || z != 0)
{
isAiming = true;
/* Vector3 lookDir = new Vector3(x, 0, z);
Quaternion lookRotation = Quaternion.LookRotation(lookDir, Vector3.up);
float step = rotationSpeed * Time.deltaTime;
player.transform.rotation = Quaternion.RotateTowards(lookRotation, transform.rotation, step);*/
float myAngle = Mathf.Atan2(x, z) * Mathf.Rad2Deg;
float bodyRotation = myAngle + player.transform.eulerAngles.y;
player.transform.Rotate( 0,myAngle,0,Space.World);
}
else { shoot();isAiming = false; }
}
void shoot()
{
if (currentMag > 0)
{
Instantiate(bullet, shotSpawn.position, shotSpawn.rotation);
currentMag--;
}
else if (currentMag=0)
{
StartCoroutine(reload());
}
else
return;
}
IEnumerator reload()
{
ammo = ammo - mag;
currentMag = mag;
yield return new WaitForSeconds(reloadTime);
}
}
well you are calling every frame playerShoot() -> not moving -> shoot().
And in the same way also playerShoot() -> not moving -> player.transform.Rotate( 0,myAngle,0,Space.World);.
I think what you rather should do is
doing the shoot only in the very first frame where both inputs are 0
for the move rather set the rotation instead of increasing it
Something like
private bool lastFrameMoved;
public void playerShoot()
{
float x = shootJS.Horizontal;
float z = shootJS.Vertical;
if (x != 0 || z != 0)
{
var lookDir = new Vector3(x, 0, z);
var lookRotation = Quaternion.LookRotation(lookDir, Vector3.up);
player.transform.rotation = lookRotation;
lastFrameMoved = true;
}
else
{
if(lastFrameMoved)
{
shoot();
}
lastFrameMoved = false;
}
}
I solved the look rotation in Bolt (because it helps me visualize). I'll solve the shoot part soon. I'm using the wonderful Joystick Pack by Fenerax Studios.
https://assetstore.unity.com/publishers/32730
The camera is child of one soldier only and also the target is this soldier.
And the script attached to the camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public Transform target;
public float speed = 0.1f;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
transform.RotateAround(target.transform.position, new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
}
}
But now I want to do two things. To make the camera to rotate around the whole soldiers and not only the specific one. And also to make the camera stop slowly when it's facing the soldiers. Now the camera is behind when starting the game.
Using a bool flag if true to make the camera rotate around the soldiers until it's facing them then stop rotation and keep moving with the soldiers.
If unchecked false make the camera rotating around the solders none stop.
UPDATE what I tried so far:
This code will make it rotating around all the soldiers and it's working fine:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public float speed = 0.1f;
private List<GameObject> Soldiers = new List<GameObject>();
// Use this for initialization
void Start()
{
Soldiers.AddRange(GameObject.FindGameObjectsWithTag("Soldier"));
}
// Update is called once per frame
void Update()
{
RotateAround();
}
private void RotateAround()
{
transform.RotateAround(GetAverageLocationOfSoliders(), new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in Soldiers)
total += soldier.transform.position;
return total / Soldiers.Count(); // Assuming Soldiers is List<Soldier>
}
}
Then I tried to add a slowDown bool flag variable, But I messed it all and it's not working at all.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public float speed = 0.1f;
public bool slowDown = false;
private List<Vector3> SoldiersPositions = new List<Vector3>();
private List<Vector3> SoldiersFacingDirection = new List<Vector3>();
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void FixedUpdate()
{
RotateAround();
}
private void RotateAround()
{
var getSoldiers = GameObject.FindGameObjectsWithTag("Soldier");
foreach (GameObject soldier in getSoldiers)
{
SoldiersPositions.Add(soldier.transform.position);
SoldiersFacingDirection.Add(soldier.transform.forward);
}
var Center = GetAverageLocationOfSoliders();
var FacingDirections = GetAverageFacingDirectionOfSoldiers();
if (slowDown == true)
{
var D = transform.position - Center;
var CamAngle = Vector3.Angle(D, FacingDirections);
speed = speed - CamAngle;
}
transform.RotateAround(Center, new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
SoldiersPositions = new List<Vector3>();
SoldiersFacingDirection = new List<Vector3>();
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in SoldiersPositions)
total += soldier;
return total / SoldiersPositions.Count(); // Assuming Soldiers is List<Soldier>
}
private Vector3 GetAverageFacingDirectionOfSoldiers()
{
var total = new Vector3();
foreach (var soldierfacingdir in SoldiersFacingDirection)
total += soldierfacingdir;
return total / SoldiersFacingDirection.Count();
}
}
I'm not sure if the first code example only for the rotation is fine the way I wrote it. It's working but not sure if this is a good way to do the code ?
It seems to me that in the first code only the rotation the camera is a bit shaking or stuttering I mean the camera is not moving smooth when rotating around. It's almost hard to see in the game view in the editor but you can see it a bit in the scene view I think.
The reason I'm calling RotateAround(); in the Update is that the soldiers are in a move they are walking forward non stop.
How should I do the slowDown part ?
UPDATE 2:
This is the full coed now:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
[Header("Spin")]
public bool spin = false;
public Vector3 Direction;
[Range(0, 300)]
public float speed = 10f;
public bool randomSpeed = false;
public bool randomDirection = false;
[Range(0f, 100f)]
public float timeDirChange;
public Vector3 defaultDirection;
[Space(5)]
[Header("Move in circles")]
public bool moveInCircles = true;
public GameObject rotateAroundTarget;
public Vector3 axis;//by which axis it will rotate. x,y or z.
public float rotationSpeed; //or the speed of rotation.
public float upperLimit, lowerLimit, delay;// upperLimit & lowerLimit: heighest & lowest height;
public bool randomHeight = false;
public bool stopRotatingWhenFacing = false;
private float height, prevHeight, time;//height:height it is trying to reach(randomly generated); prevHeight:stores last value of height;delay in radomness;
[Space(5)]
[Header("Follow objects")]
public GameObject[] objectsToFollow;
public bool randomFollow;
private float nextRotationTime = 0f;
private int counter = 0;
private List<GameObject> Soldiers = new List<GameObject>();
// Use this for initialization
void Start()
{
Soldiers.AddRange(GameObject.FindGameObjectsWithTag("Soldier"));
}
private void Update()
{
if (randomSpeed)
{
speed = UnityEngine.Random.Range(0, 300);
}
if (spin)
{
if (randomDirection == false)
{
nextRotationTime = 0;
timeDirChange = 0;
Direction = defaultDirection;
}
else
{
if (Time.time > nextRotationTime)
{
nextRotationTime += timeDirChange;
RandomDirection();
}
}
transform.Rotate(Direction, speed * Time.deltaTime);
}
else
{
timeDirChange = 0;
randomDirection = false;
randomSpeed = false;
}
if (moveInCircles)
{
MoveInCircles();
}
}
private void RandomDirection()
{
Direction = new Vector3(UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1));
while (Direction == new Vector3(0, 0, 0))
{
counter++;
Direction = new Vector3(UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1));
if (counter == 2)
{
Direction = new Vector3(1, 0, 0);
break;
}
}
counter = 0;
}
private void MoveInCircles()
{
var F = GetAverageDirectionsOfSoliders();
var D = transform.position - GetAverageLocationOfSoliders();
var angle = Vector3.Angle(D, F);
if (angle < 5f)
{
rotationSpeed -= 0.1f;
}
transform.RotateAround(GetAverageLocationOfSoliders(), axis, rotationSpeed);
time += Time.deltaTime;
//Sets value of 'height' randomly within 'upperLimit' & 'lowerLimit' after delay
if (time > delay)
{
prevHeight = height;
if (randomHeight)
{
height = UnityEngine.Random.Range(lowerLimit, upperLimit);
}
time = 0;
}
if (randomHeight == false)
{
height = transform.position.y;
}
if (randomHeight)
{
//Mathf.Lerp changes height from 'prevHeight' to 'height' gradually (smooth transition)
transform.position = new Vector3(transform.position.x, Mathf.Lerp(prevHeight, height, time), transform.position.z);
}
else
{
transform.position = new Vector3(transform.position.x, height, transform.position.z);
}
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in Soldiers)
{
total += soldier.transform.position;
}
return total / Soldiers.Count(); // Assuming Soldiers is List<Soldier>
}
private Vector3 GetAverageDirectionsOfSoliders()
{
var totalf = new Vector3();
foreach (var soldier in Soldiers)
{
totalf += soldier.transform.forward;
}
return totalf / Soldiers.Count();
}
}
The RotateAround part is working fine:
transform.RotateAround(GetAverageLocationOfSoliders(), axis, rotationSpeed);
But the slow down part is not working. It's not slowing down at all when the camera is facing the soldiers.
This is how I calculate the average transform.forward vector of all the soldiers:
private Vector3 GetAverageDirectionsOfSoliders()
{
var totalf = new Vector3();
foreach (var soldier in Soldiers)
{
totalf += soldier.transform.forward;
}
return totalf / Soldiers.Count();
}
Then inside the MoveInCircles method I did:
var F = GetAverageDirectionsOfSoliders();
var D = transform.position - GetAverageLocationOfSoliders();
var angle = Vector3.Angle(D, F);
if (angle < 5f)
{
rotationSpeed -= 0.1f;
}
But it's never getting to the line:
rotationSpeed -= 0.1f;
To rotate around all the soldiers:
Get the center of the all the soldiers (sum the world position of all soldiers and divide by N number of soldiers)
Get the maximum distance of the soldiers from the center
Rotate the camera about the center, and ensure that it is further than the max distance from the center
To slow the camera down when facing the soldiers' front:
Average out the transform.forward vector of all the soldiers. We call this vector F. This is fair since all your soldiers will typically be facing in the same general direction for this request to even make sense.
Calculate the direction D, which is the direction from the soldiers' center to the camera. This is easy: D = camera.transform.position - soldiersCenter
Finally, find the acute angle between D and F, using Vector3.Angle(). If this angle is lower than a certain threshold, decrease the moveSpeed of the camera.
The actual code is easy to write, but I'll let you practice. Let me know if you need any help
From the sounds of it, it seems you have it already able to orbit around a single soldier, so do to more than one, simply take the average of their locations.
Pseudo code:
transform.RotateAround(GetAverageLocationOfSoliders(), ...);
...
private static Vector3 GetAverageLocationOfSoliders
{
var total = new Vector3();
foreach(var soldier in Soldiers)
total += soldier.transform.position;
return total / Soliders.Count(); // Assuming Soldiers is List<Soldier>
}
Now, Vector3 might not have stuff like Vector3 += Vector3 or Vector3 / int, but if that's the case just create your own methods were you do that manually (adding vectorA.x + vectorB.x, and vectorA.x / num, etc.
As far as making the camera stop when it's in front, that's a bit trickier. You might want to do some checks first to make sure they all have the same rotation, and then check, each Update, if the look at rotation of the camera will point to one of the soldiers.
But, if you want it to slow down, then, instead of checking if the lookAtRotation can point to a soldier, check if it can point to some offset of the camera's rotation, like so:
Pseudo Code:
lookRotation(transform.Rotation + offset) // Use something like this to find Soldiers[0]
Then, if that finds one, you can use a Lerp on your speed to lerp back down to a speed of 0.
You will also have to maintain a List<Soldier> or Soldier[] somehow.
I created an 3dobject and set a game object as target, and added the below code to main camera. I am able to zoom into the 3d object, but im not able to zoom out of it. How to zoom out? i.e to go back to original position.
using System.Collections;
using UnityEngine;
public class zoo22 : MonoBehaviour
{
public float movespeed = 35.0f;
//you need to say how far from the object the camera will stop
public float minimumDistanceFromTarget = 5f;
public GameObject targetobject;
private bool movingtowardstarget = false;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(1))
{
if (movingtowardstarget == true)
{
movingtowardstarget = false;
}
else
{
movingtowardstarget = true;
}
}
if (movingtowardstarget)
{
movetowardstarget(targetobject);
}
}
public void movetowardstarget(GameObject target)
{
if(Vector3.Distance(transform.position, target.transform.position) > minimumDistanceFromTarget) //we move only if we are further than the minimum distance
{
transform.position = Vector3.MoveTowards(transform.position, target.transform.position, movespeed * Time.deltaTime);
} else //otherwise, we stop moving
{
movingtowardstarget = false;
}
}
}
I not got your movingtoward bool but you can handle your zoom easy.
First rotate your camera to look at your object and later apply zoom:
For example to zoom whith the mouse Wheel in a ortho camera you need to handle orthographicSize:
int orthographicSizeMin = 1;
int orthographicSizeMax = 6;
function Update()
{
transform.LookAt(target);
if (Input.GetAxis("Mouse ScrollWheel") > 0) // forward
{
Camera.main.orthographicSize++;
}
if (Input.GetAxis("Mouse ScrollWheel") < 0) // back
{
Camera.main.orthographicSize--;
}
}
Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize, orthographicSizeMin, orthographicSizeMax );
For a perspective camera you need to handle field of view:
float minFov = 10f;
float maxFov = 90f;
float sensitivity = 10f;
function Update()
{
transform.LookAt(target);
float fov = Camera.main.fieldOfView;
fov += Input.GetAxis("Mouse ScrollWheel") * sensitivity;
fov = Mathf.Clamp(fov, minFov, maxFov);
Camera.main.fieldOfView = fov;
}
Easiest way imo:
Add object for original position as well:
public GameObject targetobject, originalPosObj;
Then pass it as target:
movetowardstarget(movingtowardstarget ? targetObject : originalPosObj);
you can use the same function to zoom in and zoom out. please check the example below. Enter negative velocity to move backwards.
void Update()
{
if (Input.GetMouseButtonDown(1)) //move backward
movetowardstarget(targetobject, true);
if (Input.GetMouseButtonDown(0)) //move forward
movetowardstarget(targetobject, false);
}
public void movetowardstarget(GameObject target, bool backwards)
{
float dir = backwards?-1.0f:1.0f;
actualDist = Vector3.Distance(transform.position, target.transform.position);
if (Vector3.Distance(transform.position, target.transform.position) > minimumDistanceFromTarget) //we move only if we are further than the minimum distance
{
transform.position = Vector3.MoveTowards(transform.position, target.transform.position, dir*movespeed * Time.deltaTime);
}
else //otherwise, we stop moving
{
movingtowardstarget = false;
}
}
I imagine you will want to do this will the Mouse Wheel.
public class CameraConrol : MonoBehaviour
{
Vector3 centerPosition;//positon of object you want to zoom in and out of
float MaxZoom = 3f;
void Update()
{
//mouse wheel chaned
if (Input.mouseScrollDelta.y !=0)
{
ZoomCamera();
}
}
public void ZoomCamera()
{
Vector3 newPosition = Vector3.MoveTowards(
transform.position, centerPosition, Input.mouseScrollDelta.y);
if(newPosition.y >= (centerPosition.y + MaxZoom ))
{
transform.position = newPosition;
}
}
}
I'm making a 2D platformer. Here's my code so far. The character jumps only when touching the ground as it should - but the code for double jumping doesn't work. Any help is appreciated. I'm new at scripting and I don't understand what I did wrong?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
public float speed = 12f, jumpHeight = 30f;
Rigidbody2D playerBody;
Transform playerTrans, tagGround;
bool isGrounded = false;
public LayerMask playerMask;
public float maxJumps = 2;
public float jumpsLeft = 2;
// Use this for initialization
void Start ()
{
playerBody = this.GetComponent<Rigidbody2D>();
playerTrans = this.transform;
tagGround = GameObject.Find(this.name + "/tag_Ground").transform;
}
// Update is called once per frame
public void FixedUpdate ()
{
isGrounded = Physics2D.Linecast(playerTrans.position, tagGround.position, playerMask);
Move();
Jump();
DoubleJump();
}
private void Move()
{
float move = Input.GetAxisRaw("Horizontal") * speed;
playerBody.velocity = new Vector2(move, playerBody.velocity.y);
}
private void Jump()
{
if (isGrounded)
{
if (Input.GetButtonDown("Jump"))
{
playerBody.velocity = new Vector2(playerBody.velocity.x, jumpHeight);
}
}
}
private void DoubleJump()
{
if (Input.GetButtonDown("Jump") && jumpsLeft > 0)
{
Jump();
jumpsLeft--;
}
if (isGrounded)
{
jumpsLeft = maxJumps;
}
}
}
Your code doesn't make much sense. You should handle your jumping in one method and handle it something like this:
private void HandleJump()
{
if(isGrounded) {
jumpsLeft = maxJumps;
}
if(Input.GetButtonDown("Jump") && jumpsLeft > 0) {
playerBody.velocity = new Vector2(playerBody.velocity.x, jumpHeight);
jumpsLeft--;
}
}
This way you can make triple jumps or however many jumps you want.
Try replacing your Jump method code with the DoubleJump method's code and remove the check for IsGrounded before applying the jump. Otherwise your character has to be on the ground every time. Then remove the DoubleJump method as it is no longer needed. If you're utilizing the DoubleJump as an added skill later in your game then just increase maxJumps as your player earns the skill. Set it to 1 initially so that they have to hit the ground every time.
private void Jump() {
if (isGrounded) {
jumpsLeft = maxJumps;
}
if (Input.GetButtonDown("Jump") && jumpsLeft > 0) {
playerBody.velocity = new Vector2(playerBody.velocity.x, jumpHeight);
jumpsLeft--;
}
}