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
Related
I am a beginner in Unity developing a 2D top-down mobile game. I am trying to create an enemy movement script that mimics the pattern of the leech enemy below:
This enemy is constantly trying to move towards the player but even though it can move quite quickly, due to its momentum, you are able to kite it as it cannot make a sharp turn without first taking some time to build speed in another direction.
I have created a script for enemies to constantly be targeting the player based on the player's current position but it is too difficult to dodge my enemies as they are able to turn instantly when the player does and maintain a constant speed. I would like to balance them to be more like this leech enemy so the player can dodge them by taking advantage of the enemy's current momentum with proper timing. How can I create this momentum effect for my enemies?
If you're using Unity's physics here's a way to do this nicely:
Walkable.cs
Create a modular component that all walkable game objects will use. The purpose of the component is to keep the object moving in the specified direction while stabilising the forces. It uses the values you configure in the inspector for speed and force. It does the movement inside of FixedUpdate as physics movement require it.
public class Walkable : MonoBehaviour {
private const float ForcePower = 10f;
public new Rigidbody2D rigidbody;
public float speed = 2f;
public float force = 2f;
private Vector2 direction;
public void MoveTo (Vector2 direction) {
this.direction = direction;
}
public void Stop() {
MoveTo(Vector2.zero);
}
private void FixedUpdate() {
var desiredVelocity = direction * speed;
var deltaVelocity = desiredVelocity - rigidbody.velocity;
Vector3 moveForce = deltaVelocity * (force * ForcePower * Time.fixedDeltaTime);
rigidbody.AddForce(moveForce);
}
}
Character.cs
This is a simple example of character that will follow a target. Notice how all it's doing is passing the direction to the walkable from inside an Update function.
public class Character : MonoBehaviour {
public Transform target;
public Walkable walkable;
private void Update() {
var directionTowardsTarget = (target.position - this.transform.position).normalized;
walkable.MoveTo(directionTowardsTarget);
}
}
Configurations
By configuring move and force variables you can get a variety of movement styles, some that can move fast but take a long time to ramp up, some that ramp up fast but move slowly overall.
You can also play around with with mass and linear drag on the Rigidbody2D to get even more control over the movement style.
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.
Good day, I'm making a 2D platformer game and I'm trying to make to cam follow the player. But ignore the y-axis so when the player jumps the cam stays in positions instead of following the player.
Example (see asset pack demo): https://ansimuz.itch.io/gothicvania-church-pack
How can I do this using Cinemachine?
You don't have to override the camera's Y value in your camera controller script. This would be a very basic implementation:
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour {
public GameObject player; //Public variable to store a reference to the player game object
public bool followY = false;
private Vector3 offset; //Private variable to store the offset distance between the player and camera
// Use this for initialization
void Start ()
{
//Calculate and store the offset value by getting the distance between the player's position and camera's position.
offset = transform.position - player.transform.position;
}
// LateUpdate is called after Update each frame
void LateUpdate ()
{
// Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
if(followY)
{
transform.position = player.transform.position + offset; // we should follow the player Y movements, so we copy the entire position vector
}
else
{
transform.position = new Vector3(player.transform.position.x, transform.position.y, player.transform.position.z) + offset; // we just copy the X and Z values
}
}
}
Attach this script to the camera and you can enable or disable the Y-axis movement by setting the boolean accordingly. In case you will never need this functionality, just keep the line in the else block.
I hope this will help you!
I am using unity 2018.3.5f1 so a few solutions to this problem don't work.
Starting from the Roll-A-Ball demo project, I want to extend the camera script to follow the player, but also keeping track of the direction of movement. Ex: If the ball starts moving to the side, I need the camera to rotate around the player's axis to position behind him, and then start following him.
I have tried making the camera a child to the ball i'm trying to control and i've tried making a script but it won't follow the ball correctly it keeps rotating the camera as well as the ball (i'm using this bit of code and trying to modify it as it's the only one that works)
here is the code I have at the moment:
using UnityEngine;
using System.Collections;
public class CompleteCameraController : MonoBehaviour
{
public GameObject player; //Public variable to store a reference to the player game object
private Vector3 offset; //Private variable to store the offset distance between the player and camera
// Use this for initialization
void Start()
{
//Calculate and store the offset value by getting the distance between the player's position and camera's position.
offset = transform.position - player.transform.position;
}
// LateUpdate is called after Update each frame
void LateUpdate()
{
// Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
transform.position = player.transform.position + offset;
}
}
I understand why it is rotating but no reasearch is helping me find out how to lock the camera so it is looking behind the ball at all times
Have you tried adding some restraints to your camera? If it is only supposed to turn to follow the ball, you can freeze the position of 2 axes (x and z), and only let the camera rotate around the y axis of the ball.
You can play around with the restraints on the Inspector, or use GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeRotationX; in the camera script.
(EDIT) Sorry, this is how you would do it if the gameObject has a rigidbody, but the idea is the same if it doesn't have one.
When you're setting the position or rotation of the camera, think about which components of the position/rotation you actually want to change (x,y,z).
Use offset = new Vector3 (offset.x, offset.y, offset.z)and replace anything that shouldn't change with a constant.
Also, when you made the Camera the child of the ball, you could have set it so that every frame, the Camera updates in such a way that it won't roll with the ball. You could do this by putting code in the update method of the camera that sets the component x, y, or z equal to some constant. Whatever axis the ground plane is on is probably the correct choice.
If you want the same camera angle that the camera should follow while following the ball (similar to Temple Run), then try the below code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class CompleteCameraController : MonoBehaviour
{
public Transform Player;
public float distanceFromObject = 3f;
void Update()
{
Vector3 lookOnObject = Player.position - transform.position;
lookOnObject = Player.position - transform.position;
transform.forward = lookOnObject.normalized;
Vector3 playerLastPosition;
playerLastPosition = Player.position - lookOnObject.normalized * distanceFromObject;
playerLastPosition.y = Player.position.y + distanceFromObject / 2;
transform.position = playerLastPosition;
}
When the ball moves left or right, the camera will follow the same angle as the ball moves towards.
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