I am making this game in unity. It is a 2d race car game where the player is a racer and has to navigate through the road avoiding crashing into cones or other other cars that are also driving on the road. I've created a path for the other NPC cars that are driving on the road and that part works. Those cars follow the path the way I want them to. But what I want to do now is make the NPC car sprites rotate towards the next path point.
So for example if the vehicle is switching lanes or turning a corner, the car should rotate and point towards the next point in their path. This is the code I have:
public Transform[] waypoints; //array to hold all the waypoints in the sprite's path
[SerializeField]
public float moveSpeed = 2.0f;
public int wayPointIndex = 0;
// Start is called before the first frame update
void Start()
{
transform.position = waypoints[wayPointIndex].transform.position;
}
// Update is called once per frame
void Update()
{
Move();
}
public void Move(){
if(wayPointIndex <= waypoints.Length - 1){
transform.position = Vector3.MoveTowards(transform.position, waypoints[wayPointIndex].transform.position, moveSpeed * Time.deltaTime);
if(transform.position == waypoints[wayPointIndex].transform.position){
wayPointIndex+=1;
}
}
}
This is a bird's eye view game by the way. So the vehicles are seen from the top down.
You could use the transform.rotate method. The method uses an angle input, you could calculate the desired angle geometrically with your current orientation angle and the angle to the next waypoint.
Related
I want a character that simply walks forward until it hits a wall, then it does a 180 degree spin and repeats the action.
Making him walk forward is easy, how do I program him hitting the wall?
My current code:
public class Enemy : MonoBehaviour
{
public float speed = 5;
public Vector3 userDirection = Vector3.forward;
// Update is called once per frame
void Update()
{
transform.position += userDirection * speed * Time.deltaTime;
}
}
You can use raycast to detect walls and avoid them.
Raycast in Unity is a Physics function that projects a Ray into the scene, returning a boolean value if a target was successfully hit
The following code is a simple demenstration of raycast. Distance determine how far you ray is casted and layermask determine which layers ray should detect. Therefore, you must put your walls in a Layer and sit this variable equal to that:
public float distance;
public LayerMask wallLayerMask;
public Vector3 userDirection = Vector3.forward;
void Update()
{
if (Physics.Raycast(transform.position, userDirection, distance, wallLayerMask))
{
// rotate, possibly:
// userDirection *= -1
}
transform.position += userDirection * speed * Time.deltaTime;
}
UPDATE
As stated in comments, you can also use colliders. To use colliders, you need to add another empty gameObject to your enemy, add a SphereCollider to it. Sphere Collider's radius determines how far you want to detect walls. Then add the following code to the second object:
// a reference to your enemy controller class
public Enemy enemy;
private void OnCollisionEnter(Collider other)
{
enemy.Rotate();
}
The OnCollisionEnter is called whenever an object, which has a collider, collides with our object. You need to assign a layer to this new object (wallCheck) and another to your walls. Then from Edit -> Project Settings -> Physics uncheck the collision of wallCheck with any layer other than your walls layer.
I'm doing a simple game to get started with unity, there's a cube who goes straight and dodge other cubes (obstacles) which are spawned randomly. To make the obstacle always spawn in front of the player I set up a code that makes the 7 spawn position (the blocks get generated in them randomly) follow the player's coordinates but adding 100 to the Z so they get generated not upside the player. Now, my problem is that when generated the obstacle also changes their X position, making them fall from the platform when I go to the right or to the left with the player. How can I make they follow only the Z position of the player and not the X?
Here is the code that makes the spawners change position:
public class MoveSpawn : MonoBehaviour
{
public Transform player;
public Vector3 offset;
// Update is called once per frame
void Update()
{
transform.position = player.position + offset;
}
}
I would simply multiply the player's position by (0,0,1) (in other words, Vector3.forward) before adding it to the offset:
public class MoveSpawn : MonoBehaviour
{
public Transform player;
public Vector3 offset;
// Update is called once per frame
void Update()
{
transform.position = player.position * Vector3.forward + offset;
}
}
Oh, that's pretty easy.
So if you only want to look at the Z(or any other) coordinates of the Cube or any object in Unity you can simply use:
transform.position.z
That's the same thing you would do with vectors. Something like that:
Vector3 offset = ...;
Debug.Log(offset.x) //returns x coordinate of offset
So my game is sort of like a 3d top down shooter, so I want my gun to shoot wherever the mouse is and it wont go to the mouse unless im shooting down. If you've seen brackyes game called ball wars, im sort of trying to replicate one like that but the projectile is not shooting the right way.
I got my script from blackthornprods ranged combat tutorial (which is for 2d so maybe thats the issue but I dont know how to solve it) :
public float speed;
public float lifeTime;
private void Start()
{
Invoke("DestoryProjectile", lifeTime);
}
private void Update()
{
transform.Translate(transform.up * speed * Time.deltaTime);
}
void DestroyProjectile()
{
Destroy(gameObject);
}
Appreciate anyone to try!
Here is my other script:
Camera mainCam;
public GameObject projectile;
public Transform shotPoint;
private float timeBtwShots;
public float startTimeBtwShots;
void Awake()
{
mainCam = Camera.main;
}
void Update()
{
float objectDepthFromCamera = Vector3.Dot(
transform.position - mainCam.transform.position,
mainCam.transform.forward);
Vector3 cursorWorldPosition = mainCam.ScreenToWorldPoint(Input.mousePosition
+ Vector3.forward * objectDepthFromCamera);
Vector3 localUpNeeded = Vector3.Cross(Vector3.forward,
cursorWorldPosition - transform.position);
transform.rotation = Quaternion.LookRotation(Vector3.forward, localUpNeeded);
if(timeBtwShots <= 0)
{
if (Input.GetMouseButtonDown(0))
{
Instantiate(projectile, shotPoint.position, transform.rotation);
timeBtwShots = startTimeBtwShots;
}
}
else
{
timeBtwShots -= Time.deltaTime;
}
}
Projectile not shooting direction of my weapon. Simple solution -
First instantiate or pool the instance of projectile.
Set rotation of projection from the rotation of weapon & set location to spawn point
Now fire, or whatever strategy you are using
Consider Global rotation, if you need help, tell me, I will edit and give a snippet of code.
This should work. If doesn't post all necessary code, I will give a better solution.
Here is sample github project I created, just for you. I opened Unity nearly after a year. Please check all the versions.
Must check :
firing in facing direction 💋
just instantiate at spawn point
just added some rotation
I think this should give you concept.
Press X for a rantom rotation
Press Space to shoot a projectile :lol:
The white cube shows that it always shoots at a constant direction
Ok, I have a 3D Unity game built for iOS where these controls will be implemented (in a first person shooter manner):
Camera follows just behind character
Keeping finger on screen makes character walk, finger up makes it stop
THIS is the problem: wherever the user has started touching the screen, whatever direction they drag (forward, backwards, left right) the character will walk indefinitely in that direction.
This must have done already but I cant find anything anywhere. I have the camera as a child of the character, so that's taken care of but for char movement all I have is:
void Update()
{
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector3 target = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, -10f));
transform.Translate(Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime) - transform.position);
}
Which doesn't work as needed. What can I do here?
You can just try to use any king of UI joysticks (https://assetstore.unity.com/packages/tools/input-management/joystick-pack-107631) for example
And access its parameters something like this:
public class TestMovement : MonoBehaviour
{
public float Speed;
public FloatingJoystick Joystick; //Set in the inspector, prefab from the asset
private void Update()
{
transform.Translate(new Vector2(Joystick.Horizontal, Joystick.Vertical) * Speed * Time.deltaTime);
}
}
I am trying to instantiate a prefab, a fireball, from a baddie, and at the time of instantiation pass the current player position to the fireball and use this to target the fireball at the player. The fireball translates/moves forward on its transform.forward vector. Thus the fireball should head from the baddie towards the player's position at the time the fireball was created.
What I am finding is that the direction is being set (via the transform.lookat() function on the fireball), but it is almost always the wrong direction. It is not 90 or 180 off. How much it is off by depends on where the player is in respect to the baddie. The pattern is symmetrical around the z axis.
Assuming the baddie is at (0,0,0):
when the player is at (0,0,10) the fireballs head directly towards the player
when the player is at (0,0,-10) the fireballs head away from the player (180 degrees. The exact opposite direction. The same direction as when the player was at (0,0,10))
when the player is at (10,0,0) the fireballs head 90 degrees away from the player (to the players right if facing the baddie)
when the player is at (-10,0,0) the fireballs head 90 degrees away from the player (to the players left if facing the baddie)
These values move smoothly as the player moves through these angles. It only ever hits the player in one direction.
I have tried the following (some of these were probably not required):
re-import all assets
create new project on a new machine to reproduce the issue.
I've tried setting the lookat variable to be:
player transform
the vector 3 world coordinate of the player (this is what is in the code below)
player.transform.position - baddie.transform.position
baddie.transform.position - player.transform.position
These all yield the same results.
Here is my code.
Code to Instantiate the fireball from the baddie.
public class Baddie : MonoBehaviour {
public GameObject fireballPrefab;
public GameObject playerGameObject;
public float countDownForFireball;
private float currentCountDownForFireball;
void Start () {
playerGameObject = GameObject.FindGameObjectWithTag("Player");
currentCountDownForFireball = 0;
}
void Update () {
if(currentCountDownForFireball <= 0)
{
GameObject newFireball = GameObject.Instantiate(fireballPrefab, transform.position, Quaternion.identity);
newFireball.GetComponent<Fireball>().SetTarget(playerGameObject.transform.position);
currentCountDownForFireball = countDownForFireball;
}
else
{
currentCountDownForFireball -= Time.deltaTime;
}
}
}
Code on the fireball
public class Fireball : MonoBehaviour {
private float moveSpeed;
private Vector3 target;
// Use this for initialization
void Start () {
moveSpeed = 15f;
}
// Update is called once per frame
void Update (){
transform.Translate(transform.forward * Time.deltaTime * moveSpeed);
}
public void SetTarget(Vector3 newTarget){
target = newTarget;
transform.LookAt(target);
}
}
The error is in the usage of Transform.Translate. Its secondary parameter is a Space argument that defaults to Space.Self. You want the space of your direction to match the space you're translating in so you want to pass in Space.World:
// transform.forward is the transform's forward vector in "world space"
transform.Translate(transform.forward * Time.deltaTime * moveSpeed, Space.World);
Alternatively, you can keep using the default Space.Self with Vector3.forward instead of transform.forward:
// Vector3.forward is (0,0,1). In "self space" this is "forward"
transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed); // Space.Self