Enemy following player with walls between - c#

I'm trying to make a script where the enemy follows the player in a 2.5D world when he can see him.
I tried to use a raycast in every direction, but the collision with the player (and the walls) only worked when the object was directly in it.
Thats why i think that the raycast collides with the enemy itself but I didn't made to manage it otherwise
[SerializeField] private float visualRange = 1000.0f;
[SerializeField] private LayerMask minotaur;
private ContactFilter2D filter;
private void Update() {
MoveToPlayer();
}
private void MoveToPlayer() {
for(int i = 0; i <= 360; i += 5) {
List<RaycastHit2D> results = new List<RaycastHit2D>();
filter.layerMask
int number = Physics2D.Raycast(transform.position, new Vector3(0, 0, i), filter, results, visualRange);
foreach (RaycastHit2D hit in results) {
if (hit.collider.tag == GameObject.FindGameObjectWithTag("Player").tag) {
Debug.Log("Collision Player");
}
}
}
}
Thats the newest solution i tried, the filter is empty because I don't know how to add two layers.
As i mentioned i try it with a filter, but i don't know how to make the filter so it would work.
I also tried to use the z-coordinates but that also doesn't work well.

Related

I have a problem with objects copy and the objects mesh in unity

So, i have a script, and two objects, one copy of the another, exactly what one does, the other does too, but in other position. The script do the following:
get the actual value of the heat variable of the object and use this for the second part;
the second part is get the heat value and check if it's higher or equal than 850,
if it is, check if the player pressed the button to transform the object mesh in another mesh
but, when the button is pressed, only the first object has it mesh changed, i already tried raycast, a lot of additional code, ineficient code and don't worked. I know i can just make two similar scripts, but i have plans to create more objects when the player wants, so, it's not going to work...
the script:
using UnityEngine;
using DG.Tweening;
public class Iron : MonoBehaviour
{
private float Heat;
private bool Heating;
[Header("Game Objects")]
[SerializeField] private GameObject WeaponCanvas;
[Header("Materials")]
[SerializeField] private Material HotIron;
[SerializeField] private Material MediumIron;
[SerializeField] private Material CoolIron;
[Space]
[Header("Meshs")]
[SerializeField] private Mesh SimpleSwordMaterial;
[Space]
[Header("Text Mesh Pro")]
[SerializeField] private TMPro.TMP_Text TemperatureText;
private bool Hot;
void Update()
{
if (Heating && Heat <= 1500)
{
Heat += 1.5f;
}
if (Heat >= 850)
{
GetComponent<Renderer>().material = HotIron;
Hot = true;
}
if (Heat >= 600 && Heat <= 849)
{
GetComponent<Renderer>().material = MediumIron;
Hot = false;
}
if (Heat <= 400)
{
GetComponent<Renderer>().material = CoolIron;
Hot = false;
}
}
void OnCollisionStay(Collision other)
{
if (other.gameObject.tag == "HeatSource")
{
Heating = true;
}
if (!(other.gameObject.tag == "HeatSource"))
{
Heating = false;
}
}
public void SimpleSword()
{
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 3.5f))
{
hit.transform.gameObject.GetComponent<MeshFilter>().mesh = SimpleSwordMaterial; // i have problems from here (i guess ;-;)
hit.transform.gameObject.GetComponent<MeshCollider>().sharedMesh = SimpleSwordMaterial;
if (hit.transform.gameObject.GetComponent<BoxCollider>() != null)
{
Destroy(hit.transform.gameObject.GetComponent<BoxCollider>());
}
if (hit.transform.gameObject.GetComponent<SphereCollider>() != null)
{
Destroy(hit.transform.gameObject.GetComponent<SphereCollider>());
}
if (hit.transform.gameObject.GetComponent<CapsuleCollider>() != null)
{
Destroy(hit.transform.gameObject.GetComponent<CapsuleCollider>());
}
transform.localScale = new Vector3(1, 1, 1);
}
WeaponCanvas.SetActive(false);
Player.onMenu = false;
Cursor.lockState = CursorLockMode.Locked;
}
void OnMouseOver()
{
if (Input.GetMouseButtonDown(1) && Hot)
{
WeaponCanvas.SetActive(true);
Player.onMenu = true;
Cursor.lockState = CursorLockMode.None;
}
TemperatureText.text = ((int)Heat).ToString() + "°";
TemperatureText.DOFade(1, 0.4f);
}
void OnMouseExit()
{
TemperatureText.DOFade(0, 0.4f);
}
}
Similar to sharedMaterial
sharedMesh is not what you want to use...
It is recommended to use this function only for reading mesh data and not for writing, since you might modify imported assets and all objects that use this mesh will be affected.
Also, be aware that is not possible to undo the changes done to this mesh.
I'm having a bit of trouble understanding the problem... are all objects with the Iron.cs getting a new mesh? if yes, it's the .sharedmesh =.
Furthermore, it's worth noting that each monobehaviour in Unity has a .GetInstanceId() method. You can compare the id of the instance you hit with your raycast and that of the one with the correct temporature.
You should also consider simply instantiating a prefab of a sword instead.

Why my bomb impact radius and explosion effect instantiate in diffrent possition than it should?

Im working on bomb system in Unity 3D. I have uploaded some explosion effects from Unity Asset Store and I want implement them into my project. I want to plant bomb with key "K" then wait 3sec to detonate it with explosion effect and give some damage to nearby objects. The problem is that explosion appears in such different position as it should. In my opinion this is Editor problem , the code looks fine. I will give you some screenshoots(https://drive.google.com/file/d/19Yzymch9RdTa-E6RkbvvyfzMWjMJHo52/view?usp=sharing)and my bomb script :
public class BoombScript : MonoBehaviour
{
public GameObject boombEffect;
[SerializeField]
private float radius;
[SerializeField]
private float force;
[SerializeField]
private int explosiveDamage;
public void Explode()
{
Instantiate(boombEffect, transform.position, Quaternion.identity);
Debug.Log("Transform" + transform);
Debug.Log("Position" + transform.position);
Collider[] colliders = Physics.OverlapSphere(transform.position, radius);
foreach(Collider rangedObject in colliders)
{
GateScript Gate = rangedObject.GetComponent<GateScript>();
Rigidbody rb = rangedObject.GetComponent<Rigidbody>();
if(Gate != null)
{
Gate.GateDestroy(explosiveDamage);
}
if(rb != null)
{
rb.AddExplosionForce(force, transform.position, radius);
}
}
}
public IEnumerator WaitForExplode()
{
yield return new WaitForSeconds(3f);
Explode();
}
}
In my opinion this is Editor problem , the code looks fine.
In general I would always doubt such a statement.
I can only guess but if I understand you correctly you rather want to use the position of your object the moment when you start the Coroutine, not the one after 3 seconds:
// instead of using the current "reansform.position" rather
// use the pre-stored position passed in via parameter
public void Explode(Vector3 position)
{
Instantiate(boombEffect, position, Quaternion.identity);
Debug.Log("Transform" + transform);
Debug.Log("Position" + position);
Collider[] colliders = Physics.OverlapSphere(position, radius);
foreach(Collider rangedObject in colliders)
{
GateScript Gate = rangedObject.GetComponent<GateScript>();
Rigidbody rb = rangedObject.GetComponent<Rigidbody>();
if(Gate != null)
{
Gate.GateDestroy(explosiveDamage);
}
if(rb != null)
{
rb.AddExplosionForce(force, position, radius);
}
}
}
// If really needed you could still also have an overload
// e.g. if at some places you actually call this method from the outside
// immediately
public void Explode()
{
Explode(transform.position);
}
public IEnumerator WaitForExplode()
{
// Store the position when the routine is started
var position = transform.position;
yield return new WaitForSeconds(3f);
// Instead of using the current position rather pass in
// the previously stored one of when the routine was started
Explode(position);
}

Photon Network Spawn Players At Different Points

I am trying to make an RTS game using Photon Networking For Unity. What I am trying to do is depending on the players in the specific room (2 in this example) all the players spawn at a different location. What I am having trouble is making a system that spawns the players at different locations and not at the same place when the game starts and PhotonNetwork.Instantiate is called. How can I use SpawnPositions With A list to check if a player is already spawned at the given location if so then it spawns at the next one I hope I covered everything if you need to know anything else just ask.
private GameObject playerPrefab; // Players Prefab
[SerializeField]
public Transform[] SpawnPositions; // 2 Spawn Positions in The unity hierarchy
public List<Vector3> spawnPoints = new List<Vector3>(); // List of spawnpoints to add to
void Start()
{
PhotonNetwork.Instantiate(playerPrefab.name, [what to do here], Quaternion.Euler(0, 0, 0));
}
Edit 2: using Transform[] SpawnPositions
private int spawnIndex;
...
void CreatePlayerObject()
{
if(spawnIndex >= SpawnPositions.length) spawnIndex = 0;
Vector3 position = SpawnPositions [spawnIndex].transform.position;
GameObject newPlayerObject = Instantiate(player, position, Quaternion.identity);
spawnIndex++;
}
...
end edit 2
You can make spawn points. I made the spawn points automatically find the right height. If you don't need auto height, you can use an empty MonoBehaviour or even use a tag. You can make many GameObjects in different positions with this script on them.
...
public class spawnPoint : MonoBehaviour {
public bool autoHeight = true;
public LayerMask putOnTopOfThese;
// Use this for initialization
void Start () {
RaycastHit hit;
Physics.Raycast (transform.position + Vector3.up * 100, -Vector3.up, out hit, 200, putOnTopOfThese);
transform.position = hit.point + Vector3.up;
}
}
To make every player spawn in a different position, you can cycle through the spawn points. Keep in mind that if you use a tag for spawn points instead of a MonoBehaviour, you would need to use GameObject.FindObjectsWithTag instead of FindObjectsOfType
For spawning in different positions:
private int spawnIndex;
...
void CreatePlayerObject()
{
spawnPoint[] sp = GameObject.FindObjectsOfType<spawnPoint> ();
if(spawnIndex >= sp.length) spawnIndex = 0;
Vector3 position = sp [spawnIndex].transform.position;
GameObject newPlayerObject = Instantiate(player, position, Quaternion.identity);
spawnIndex++;
}
...
For random spawning:
...
void CreatePlayerObject()
{
spawnPoint[] sp = GameObject.FindObjectsOfType<spawnPoint> ();
int chosen = Random.Range (0, sp.Length);
Vector3 position = sp [chosen].transform.position;
GameObject newPlayerObject = Instantiate(player, position, Quaternion.identity);
}
...
Edit: clarity
Thank you bazilbaachu(https://answers.unity.com/users/1127669/bazilbaachu.html).
I am posting my entire workflow of instantiating players at different positions:
Initially checking whether we are master client or not:
Then obtain list of players and send rpc to each of them individually on positions to spawn them.You can store an array of positions and send index in rpc.
Here is the code:
photonView = PhotonView.Get(this);
if(PhotonNetwork.IsMasterClient)
{
foreach(Player pl in PhotonNetwork.PlayerList)
{
//Debug.Log(pl);
photonView.RPC("InstantiationPlayer",pl,index);
index++;
}
}
[PunRPC]
void InstantiationPlayer(int index)
{
PhotonNetwork.Instantiate(Playerprefabs[value].name,SpawnPoints[index].transform.position, Quaternion.identity, 0);
}
Thank you.
public Transform[] spawnPoints;
private void Start()
{
int randomNumber = Random.Range(0, spawnPoints.Length);
Transform spawnPoint = spawnPoints[randomNumber];
PhotonNetwork.Instantiate(playerPrefabs.name, spawnPoint.position, Quaternion.identity);
}
Drag your GameObject points into Spawn Points

Make enemy follow you when within a certain distance

I have enemies move along a set path (way points) but I want an enemy to follow the player when you are within a certain distance of it but then when out of that distance, the enemy goes back to its way points and continues moving along the path until the player is within a certain distance again. So it keeps doing that. Below is the code I got for the enemies to move along the way points.
I am using Unity 2d and C#
[SerializeField]
Transform[] waypoints; //EnemyWayPoint;
[SerializeField]
float moveSpeed = 3f;
int waypointIndex = 0;
private void Start()
{
transform.position = waypoints[waypointIndex].transform.position;
}
private void Update()
{
Move();
}
private void Move()
{
transform.position = Vector3.MoveTowards(transform.position, waypoints[waypointIndex].transform.position, moveSpeed * Time.deltaTime);
if (transform.position == waypoints[waypointIndex].transform.position) {
waypointIndex += 1;
}
if (waypointIndex == waypoints.Length)
waypointIndex = 0;
}
}
Check for the distance between enemy and player using Vector3.Distance(otherPos,transformPos)
and made check for distance according to your choice if it's less than distVal, then enemy should follow or action performed
var distVal=5.0f;
var dis=Vector3.Distance(enemyTransform.position,playerTransform.position);
if(dis<=disVal)
{
//what enemy should do.
}
Next is your own choice for normalization of vectors you set while read for distance document here
Arslan's answer is fine -
just adding a slight change to the code so you know it can be done this way too...
var distVal=5.0f;
if (Vector3.Distance(enemyTransform.position, playerTransform.position) < disVal)
{
Debug.Log("Enemy following you");
}
It's much the same but good to know of other ways it exists.

getting my 2d sprite flip to work depending on a Transform's location from it

So, this code just isn't responding for whatever reason. I have an enemy that I'm trying to get to face the player at all times (The enemy swoops over the player's head back and forth periodically). But other than making a flip happen whenever a timer hits 0, which doesn't really work all that well, I can't get the Flip function to work. I know the Flipper function is fine; I already tested it out and everything. I'm just not sure how to tell the enemy that when the player is to the left of it, to turn, and vice versa.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class dragoonDetection : MonoBehaviour {
private Rigidbody2D rb;
private Animator anim;
public Transform Player;
private bool facingRight = true;
void Start ()
{
rb = GetComponent<Rigidbody2D> ();
anim = GetComponent<Animator> ();
}
void Update()
{
Flip();
}
void Flip()
{
if (Player.transform.localScale.x > 0) {
transform.localScale = new Vector3 (1.69f, 1.54f, 1f);
}
if (Player.transform.localScale.x < 0) {
transform.localScale = new Vector3 (-1.69f, 1.54f, 1f);
}
}
void Flipper()
{
facingRight = !facingRight;
Vector2 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
Got any ideas? I'd rather avoid using FindGameObject because it's not actually looking for the player script. It's looking for a child transform with no script attached to the player. And because I have two different player GameObjects that you can switch to anytime in the game, it wouldn't really work for me in that regard.
You will need to perform a check of some sort against the players position with the bird position if you want it to face the player at all times. A barebones method would just be to compare the x-positions of the two objects and change the scale accordingly.
void Update()
{
transform.localScale = new Vector3(getDir()*1.69f, 1.54f, 1);
}
private int getDir()
{
if (player.transform.position.x < transform.position.x)
return -1;
else
return 1;
}
You should throw some additional checks in here to keep it from updating the scale every frame when there is no change.

Categories