Can I make my enemy run towards the player faster in this code? (Unity) - performance

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour
{
public NavMeshAgent Ninja;
public GameObject Player;
public float NinjaDistanceRun = 30.0f;
void Start()
{
Ninja = GetComponent<NavMeshAgent>();
}
void Update()
{
float distance = Vector3.Distance(transform.position, Player.transform.position);
//Run towards player
if(distance < NinjaDistanceRun)
{
Vector3 dirToPlayer = transform.position - Player.transform.position;
Vector3 newPos = transform.position - dirToPlayer;
Ninja.SetDestination(newPos);
}
}
}
The code shown above is what I use to make the enemy follow the player when in range. Can I make my enemy go faster without trashing this whole script and making a new one that has a different line of thought?

Set the maximum speed for your ninja(NavMeshAgent.speed). Here is the documentation for more information:
https://docs.unity3d.com/ScriptReference/AI.NavMeshAgent-speed.html

In the START method you can set a new speed to your Navmesh agent, and this character will walk or run in the player direction.

Related

Unity Instantiate objects appear in hierarchy but not visible

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MakePipe : MonoBehaviour
{
public GameObject pipe;
float timer = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if (timer > 1)
{
Instantiate(pipe);
timer = 0;
}
}
}
I am trying to instantiate pipes using prefab, and with the code, a new set of pipes should spawn and move left from the original position where the first set of pipes spawned, but they are not visible.
They are generated as clones in the hierarchy, but when I double-click them to check the position, it points towards the first pipe position.
My guess is that new clones are generated and overlapped in the first pipe as they move together.
Please help
Thanks for your reply.
Sorry I didn't add a separate cs code 'move', I should have added gif..
The following code is to move the pipe left with certain speed. There is no problem there.
However from the 'MakePipe' code that I originally posted, I used instantiate to keep reproducing the pipe. Maybe I should add some lines to 'Start()' part to set original spawn location?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public float speed;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position += Vector3.left * speed * Time.deltaTime;
// Debug.Log(transform.position);
}
}
I had to delete photos because error message tells me I should have more than 10 reps to edit :(
I don't have enough rep to comment, I'll attempt to give you a answer and update it for what you need.
The Object.Instantiate method has some parameters that you can use to get your pipes into place.
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);
And without the overloads it will use the original prefab's parameters. So they will spawn in the same location. You have to calculate the next position and pass it in the Instantiate method (Vector3 position).
I misunderstood what you are trying to do at first. #Geeky Quentin
gave the right answer in the first comment.
[SerializeField] private GameObject pipe;
float timer = 0;
float offset = 1.5f;
void Start()
{
}
void Update()
{
timer += Time.deltaTime;
transform.position += new Vector3(-Time.deltaTime/offset, 0, 0);
if (timer > 1)
{
GameObject lastPipe = Instantiate(pipe);
lastPipe.transform.SetParent(transform);
timer = 0;
}
}
I still don't have enough rep to comment. Regarding your last changes. I tested your code out.
Are you parenting the instantiated pipe to the PipeMaker in another script? If not this is the effect it spawns but it does not move:
To make it work you need to parent the instantiated pipe and change it's position MakePipe.cs:
public GameObject pipe;
float timer = 0;
private GameObject _newPipe;
void Update()
{
timer += Time.deltaTime;
if (timer > 1)
{
//instatiate with parent on transform
_newPipe = Instantiate(pipe, transform);
//Set positiion to orginal prefab position
_newPipe.transform.position = pipe.transform.position;
timer = 0;
}
}
This is the effect:
My PipeSpawner has the Move and MakePipe scripts attached to it. And the prefab is in a hidden PipePrefab object that's unrelated to the rest of the system.
You could also set the position of the original spawn location in your Start() method as you said, it's up to you.

How to move a cube 3 second in one direction, and next 3 seconds in oppposite direction, alternatively

I am new to unity, and trying something like below, but I can either move only in one direction, or not moving at all.
My cube is a trigger, and is not using gravity. I have checked the Kitematic box. I am trying to make the cube move to and fro, so that player have difficuly collecting it.
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
public class movedanger : MonoBehaviour
{
private int mytime = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
MyMover(mytime);
}
void MyMover(int mytime)
{
if (mytime <= 3)
{
transform.Translate(Vector3.forward * Time.deltaTime);
mytime++;
}
else
{
transform.Translate(-Vector3.forward * Time.deltaTime);
mytime = 1;
}
}
}
What you are looking for is to and fro movement of an object. You can achieve this with Mathf.PingPong() function instead of using translate. I have tested it with a cube, you can set the minimum and maximum distance it should move to and the speed at which it travels. Since you want the cube to move 3 seconds in one direction at a time. You can calculate the speed as distance/time so the max distance it should travel to from the current distance and the time (3 seconds) it takes. Hope this helps.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCube : MonoBehaviour {
public float min = 2f;
public float max = 8f;
public float SpeedOfMovement = 2f;
// Start is called before the first frame update
void Start () {
}
// Update is called once per frame
void Update () {
transform.position = new Vector3 (Mathf.PingPong (Time.time * SpeedOfMovement, max - min) + min, transform.position.y, transform.position.z);
}
}
With InvokeRepeating you will call the same MoveCube method every 3 seconds.
using UnityEngine;
public class MoveDanger: MonoBehaviour
{
public bool isForward = false;
private void Start()
{
InvokeRepeating("MoveCube", 0f, 3f);
}
private void MoveCube()
{
if (isForward)
{
transform.Translate(Vector3.back);
isForward = false;
}
else
{
transform.Translate(Vector3.forward);
isForward = true;
}
}
}
Honestly the best and easiest way to do something like this, once you get used to it, is just to
Use Unity's incredibly simple animator system:
(Essentially just click "new animation" and then drag the object around as you want it animated.)
There are 100s of tutorials online explaining how to use it.
It's one of those things where once you use it and see how easy it is, you will do a "facepalm" and never bother again with other ways.
It's really "the Unity way" to achieve the goal here, dead easy and flexible.

Enemies always clumping together in unity 2d

I'm trying to make a top-down shooter game in unity 2d. But the enemies are always clumping together. Does someone knows how to avoid it?
Here's my enemy code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float moveSpeed;
public float stoppingDistance;
public Transform player;
private Rigidbody2D rb;
public GameObject effect;
public int health = 3;
public static int enemyCounter;
public SpriteRenderer enemy;
public Color hurtColor;
void Start() {
rb = GetComponent<Rigidbody2D>();
player = GameObject.FindGameObjectWithTag("Player").transform;
}
void Update() {
enemyCounter = EnemySpawner.enemyCounter;
Vector2 direction = transform.position - player.position;
if (Vector2.Distance(transform.position, player.position) > stoppingDistance) {
transform.position = Vector2.MoveTowards(transform.position, player.position,
moveSpeed * Time.deltaTime);
}
else if (Vector2.Distance(transform.position, player.position) > stoppingDistance) {
transform.position = this.transform.position;
}
}
IEnumerator Flash(){
enemy.color = hurtColor;
yield return new WaitForSeconds(0.01f);
enemy.color = Color.red;
}
void OnCollisionEnter2D(Collision2D other) {
if (other.gameObject.tag == "Bullet") {
StartCoroutine(Flash());
health -= 1;
}
if (health <= 0) {
GameObject DestroyEnemy = Instantiate(effect, transform.position, Quaternion.identity);
Destroy(this.gameObject);
Destroy(DestroyEnemy, 2f);
}
}
}
The enemies is moving towards the player, but they clump together when I move the player. I really need help.
If the enemies are moving in straight line to the player they will always clump up. If you want to ensure a minimal distance between enemies you could consider using a second larger collider on another layer but this will might end up looking bad and could make some exploits possible if too big.
The other alternative would be to change the behaviour of the enemies. Making an enemy move depending on the position of the other enemies seems complicated therefore i would simply try to add some randomness to their behaviour. Here are some ideas you could try:
-(would be my first try) switch randomly between two behaviours, 1: move straight to the player (always if very close to player), 2: move in a random direction (sometimes when further away from the player)
-don't give all your enemies the same speed
-make them move towards the player + a small random angle away from the player if far away
-...
To sum it up you will need an improved behaviour and there isn't a single solution.

Unity determining ground via raycasting 2d

Good evening!
I am trying to make a simple 2d platformer in unity without using rigidbodies, so I use raycast to determine where is the ground. I wrote this code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class comtroller : MonoBehaviour
{
private float velocity_y;
private float velocity_x;
private float speed_y = 1;
private float speed_x = 10;
private float localMinimum_y;
//mask of the platform
public LayerMask mask;
void Update()
{
// raycast to sense platforms
RaycastHit2D hit = Physics2D.Raycast((Vector2)transform.position , Vector2.down,Mathf.Infinity, mask);
if (hit)
{
localMinimum_y = hit.point.y;
}
else
{
localMinimum_y = -10;
}
//determine whether the player can fall down
// -0.6 is the distance between the player's transform.position and his legs
if(transform.position.y -0.6f < localMinimum_y)
{
speed_y = 0;
}
else
{
speed_y = 1;
}
//determine velocities
velocity_y = speed_y * Physics2D.gravity.y * Time.deltaTime;
velocity_x = Input.GetAxis("Horizontal") * speed_x * Time.deltaTime;
//movement
transform.Translate(new Vector2(velocity_x, velocity_y));
}
}
However, the player keeps stucking in the platform.
Can anyone help me where is the problem and how can I cure it?
Or if my idea is completely bad can you give any suggestion about how to do it?
Thank you
I recommend following this tutorial if you want to go the non rigidbody way of making a 2d platformer game. It shows you how to manage raycast to make a character move on ground, slope, platforms and many other things. It's really ressourceful and will probably help you a lot.

Unity StandAlone GetAxis() doesn't work if I hold 2 buttons on external keyboard

I work with standard Input.GetAxis("horizontal") and some Input.GetKeyDown on simple Update() loop.
All work on standard keyboard of my mac book pro.
Connecting a external usb keyboard to a mac book pro, and hold both "B" and "V" the Left Arrow is not detected and the axis "horizontal" doesn't work.
Also, if I hold "B" and Left Arrow the "V" key is not detected.
Any idea for a workaround?
Use this code to replicate
using UnityEngine;
using System.Collections;
public class TestKey : MonoBehaviour {
string inputState;
// Update is called once per frame
void Update ()
{
inputState = string.Format(
"\nAxis:{0}\nB:{1}\nV:{2}"
,Input.GetAxis("Horizontal")
,Input.GetKey(KeyCode.B)
,Input.GetKey(KeyCode.V)
);
}
void OnGUI()
{
GUI.Label(new Rect(0,0,Screen.width,Screen.height),inputState);
}
}
Sounds like you have an error in your code pleas, post your code ,, did you change in the GetAxis ?.. Becouse your update loop may stop when you click on another key and not moveing on to the next part of the loop.. Try to look here
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Boundary
{
public float xMin, xMax, zMin, zMax;
}
public class PlayerController : MonoBehaviour
{
public float speed;
public float tilt;
public Boundary boundary;
void FixedUpdate ()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rigidbody.velocity = movement * speed;
rigidbody.position = new Vector3
(
Mathf.Clamp (rigidbody.position.x, boundary.xMin, boundary.xMax),
0.0f,
Mathf.Clamp (rigidbody.position.z, boundary.zMin, boundary.zMax)
);
rigidbody.rotation = Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x * -tilt);
}
}
Finally I found that is not Unity related issue: is a hardware limitation of apple keyboard that doesn't track multiple key simultaneously.
I connect another high-end keyboard (called N-Key rollover) and all work fine.
Use this link to some reference about rollover capability:
http://en.wikipedia.org/wiki/Rollover_(key)

Resources