I'm trying to make a 2D multiplayer game and I encountered the next problem: animation and movement are not displayed correctely to partner. They have a small delay and the character looks judder. My annimation has 3 states: (IDLE, MOVE AND JUMP).Both objects have rigidbody component - player1,player 2. My code looks like this:
Sending position from player 1 to player 2: GameController.cs
public PlayerManager player1;
public PartenerManager player2;
void Update () // CODE TO SEND POSITION
{
if (player1.transform.position.x!=position.x || player1.transform.position.y!=position.y || player1.transform.position.z !=position.z)
{
int state = player1.getState();
position = new Vector3(player1.transform.position.x, player1.transform.position.y, player1.transform.position.z);
Dictionary<string, string> data = new Dictionary<string, string>();
data["position"] = position.x + ";" + position.y + ";" + position.z;
data["state"] = state.ToString(); // this is for the state of the annimation
socket.Emit("MOVE", new JSONObject(data));
}
}
// RECEIVING POSITION
void Start () {
socket.On("MOVED", onUserMove);
}
void onUserMove(SocketIOEvent obj)
{
string stare = obj.data.GetField("state").ToString();
stare = stare.Substring(1);
stare = stare.Substring(0, stare.Length - 1);
player2.setPositionState(JsonToVector3(JsonToString(obj.data.GetField("position").ToString(),"\"")),int.Parse(stare));
}
Recieveing and displaying the position at player 2: PartnerManager.cs
public class PartenerManager : MonoBehaviour {
public bool gotmove=false;
public float speedX = 6;
private string playerName;
public Text username;
Animator anim;
Rigidbody2D rb;
bool facingRight;
float speed;
Vector3 vec3;
int stare;
void Start () {
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
facingRight = true;
}
void Flip()
{
if ((speed> 0 && !facingRight) || (speed < 0 && facingRight))
{
facingRight = !facingRight;
Vector3 temp = transform.localScale;
temp.x *= -1;
transform.localScale = temp;
}
}
public void setPositionState(Vector3 ve,int st)
{
gotmove = true;
vec3 = ve;
stare = st;
}
void FixedUpdate ()
{
if (gotmove==true)
{
if (transform.position.x < vec3.x)
{
Debug.Log("RIGHT");
speed = speedX;
}
if (transform.position.x > vec3.x)
{
Debug.Log("Left");
speed= -speedX;
}
if (transform.position.x == vec3.x)
{
speed = 0;
}
transform.position = vec3;
Flip();
anim.SetInteger("State", stare);
gotmove = false;
}
}
}
Player 1 code: PlayerManager.cs
public class PlayerManager : MonoBehaviour {
public float speedX=6;
public float jumpSpeedY=300;
private string playerName;
public Text username;
Animator anim;
Rigidbody2D rb;
bool facingRight;
bool jumping;
bool grounded;
float speed;
int numJumps = 0;
void Start ()
{
anim = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
facingRight = true;
grounded = false;
}
public int getState()
{
return anim.GetInteger("State");
}
void Update ()
{
MovePlayer(speed);
Flip();
}
void MovePlayer(float playerSpeed)
{
if ((playerSpeed < 0 && !jumping) || (playerSpeed>0 && !jumping))
{
anim.SetInteger("State", 1);
}
if(playerSpeed==0 && !jumping)
{
anim.SetInteger("State", 0);
}
rb.velocity = new Vector3(speed, rb.velocity.y, 0);
}
void Flip()
{
if((speed>0 && !facingRight) || (speed<0 && facingRight))
{
facingRight = !facingRight;
Vector3 temp = transform.localScale;
temp.x *= -1;
transform.localScale = temp;
}
}
void OnCollisionEnter2D(Collision2D other)
{
if(other.gameObject.tag=="ground")
{
jumping = false;
numJumps = 0;
grounded = true;
anim.SetInteger("State", 0);
}
}
public void WalkLeft()
{
speed = -speedX;
}
public void WalkRight()
{
speed = speedX;
}
public void StopMoving()
{
speed = 0;
}
public void Jump()
{
grounded = false;
if (grounded == true && numJumps >= 2)
{
numJumps = 0;
}
if (numJumps < 2 )
{
jumping = true;
if (numJumps == 0)
{
rb.AddForce(new Vector2(rb.velocity.x, jumpSpeedY));
}
else
{
rb.AddForce(new Vector2(rb.velocity.x, jumpSpeedY-100));
}
anim.SetInteger("State", 2);
numJumps++;
}
}
}
I resolved the problem. When you send the position you have also to send the rotation - quaternion . Here is my solution:
IMPORTANT: in the rigidbodycomponent, the z ax rotation must be checked
PartnerManager.cs - partner. The object that have to be sync
public class PartenerManager : MonoBehaviour
public Text username;
Vector3 targetPosition;
Quaternion targetRotation;
Animator anim;
bool facingRight;
int state;
void Start()
{
anim = GetComponent<Animator>();
facingRight = true;
anim.SetInteger("State", 0);
}
void Flip()
{
facingRight = !facingRight;
Vector3 temp = transform.localScale;
temp.x *= -1;
transform.localScale = temp;
}
public void setPositionState(Vector3 pozitie, Quaternion rotatie, int stare)
{
targetPosition = pozitie;
targetRotation = rotatie;
state = stare;
}
void ApplyMovement()
{
Debug.Log("pozitie actuala:" + transform.position.x + " pozitie mutata: " + targetPosition.x);
if (transform.position.x < targetPosition.x)
{
if (facingRight != true)
{
Flip();
facingRight = true;
}
}
if (transform.position.x > targetPosition.x)
{
if (facingRight == true)
{
Flip();
facingRight = false;
}
}
transform.position = Vector3.Lerp(transform.position, targetPosition, 0.5f);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, 0.5f);
anim.SetInteger("State", state);
}
void FixedUpdate()
{
ApplyMovement();
}
GameController.cs - the controlloer. Here i send and receive the message with the position
if (player1.transform.position.x != position.x || player1.transform.position.y != position.y || player1.transform.position.z != position.z)
{
int state = player1.getState();
position = new Vector3(player1.transform.position.x, player1.transform.position.y, player1.transform.position.z);
Dictionary<string, string> data = new Dictionary<string, string>();
data["position"] = position.x + ";" + position.y + ";" + position.z;
data["state"] = state.ToString();
data["rotation"] = player1.transform.rotation.x + ";" + player1.transform.rotation.y + ";" + player1.transform.rotation.z + ";" + player1.transform.rotation.w;
socket.Emit("MOVE", new JSONObject(data));
}
Quaternion JsonToQuaternion(string target)
{
Quaternion newVector;
string[] newString = Regex.Split(target, ";");
newVector = new Quaternion(float.Parse(newString[0]), float.Parse(newString[1]), float.Parse(newString[2]),float.Parse(newString[3]));
return newVector;
}
void onUserMove(SocketIOEvent obj)
{
string stare = obj.data.GetField("state").ToString();
stare = stare.Substring(1);
stare = stare.Substring(0, stare.Length - 1);
Vector3 pozitie = JsonToVector3(JsonToString(obj.data.GetField("position").ToString(), "\""));
Quaternion rotatie= JsonToQuaternion(JsonToString(obj.data.GetField("rotation").ToString(), "\""));
int state = int.Parse(stare);
//Debug.Log("Partener: pozitie: " + pozitie + " rotatie " + rotatie + " stare: " + stare);
player2.setPositionState(pozitie,rotatie,state);
//player2.setPositionState(JsonToVector3(JsonToString(obj.data.GetField("position").ToString(),"\"")),int.Parse(stare));
}
Related
I am trying to create an enemy that is 'smart', that changes a weapon if it has no ammo left and if all its weapons are depleted of ammo find the nearest weapon and change the weapon.
So far, I have an enemy that can patrol, find player in range, chase and attack the player.
Here is the code:
public class EnemyControler : MonoBehaviour
{
[Header("Attack")]
[SerializeField] float shootingDistance =10.0f;
[SerializeField] float shootDelay = 3.5f;
[Range(0,1.0f)][SerializeField] float shootingAccuracy =0.5f;
[SerializeField] int shootDamage =5;
[SerializeField] int ammo = 1;
[Header("User Interface")]
public Transform canvasTr;
public Slider Healthbar;
[Header("Health/Damage/Death")]
public float MaxHealth;
public float Damage;
public float AttackRange;
public int deathCounter;
public Transform ammoObject;
private NavMeshAgent navAgent;
private Collider enemycollider;
private Transform PlayerTr;
private Animator EnemyAnim;
float Health;
bool showingHealthBar, alive;
bool isPatrolling =false;
bool isInShootingRange =false;
bool canResumeIdleState =true;
bool isPreparingToShoot=false;
bool isDead =false;
bool isAlerted =false;
float shootTimer = Mathf.Infinity;
AIPatrolBehavior aIPatrolBehavior = null;
void Start()
{
Health = MaxHealth;
canvasTr.gameObject.SetActive(false);
navAgent = GetComponent<NavMeshAgent>();
EnemyAnim = GetComponent<Animator>();
enemycollider = GetComponent<Collider>();
PlayerTr = GameObject.FindGameObjectWithTag("Player").transform;
aIPatrolBehavior = GetComponent<AIPatrolBehavior>();
alive = true;
ammo = 100;
StartCoroutine(Idle());
// are you sure you want to randomly change MaxHealth after settting health = maxHealth?
//the slider gets weirdly bugged
// MaxHealth = Random.Range(50, 200);
Healthbar.maxValue = MaxHealth; // set the max value to MaxHelth
}
private void Update()
{
if(isDead)return;
if(Vector3.Distance(PlayerTr.transform.position, transform.position) > 20 && !isAlerted
|| PlayerTr.GetComponent<PlayerController>().HealthBar.value <= 0.0f){
StopAllCoroutines();
GetComponent<AIPatrolBehavior>().enabled =true;
return;
}
if(Vector3.Distance(PlayerTr.transform.position, transform.position) < 20 && isAlerted) isAlerted=false;
isInShootingRange = DistanceToPlayer() < shootingDistance &&
DistanceToPlayer() > AttackRange - 0.5f &&
PlayerTr.GetComponent<PlayerController>().HealthBar.value > 0;
if(isInShootingRange)
{
if(canResumeIdleState){
StopAllCoroutines();
canResumeIdleState=false;
}
ProcessShooting();
} else{
if(!canResumeIdleState){
isPreparingToShoot =false;
StartCoroutine(Idle());
canResumeIdleState =true;
navAgent.enabled =true;
}
}
}
private void ProcessShooting()
{
if(!isPreparingToShoot) shootTimer +=Time.deltaTime;
navAgent.enabled =false;
transform.LookAt(PlayerTr);
float randomProbability =Random.Range(0,1.0f);
if(shootTimer > shootDelay){
ShootAtPlayer();
}
EnemyAnim.SetFloat("MovmentSpeed", 0, 0.3f, Time.deltaTime);
}
private void ShootAtPlayer(){
if(isPreparingToShoot)return;
EnemyAnim.SetBool("PrepareAttack", false);
shootTimer =0.0f;
isPreparingToShoot = true;
EnemyAnim.SetTrigger("shoot");
}
public void ShootPlayerAnimationEvent(){
Debug.Log("Player got shot");
float randomAccuracy = Random.Range(0, 1.0f);
bool willHitTarget = randomAccuracy > 1.0f - shootingAccuracy;
if(willHitTarget && DistanceToPlayer() < shootingDistance){
PlayerTr.GetComponent<PlayerController>().DoDamage(shootDamage,true);
}
GetComponentInChildren<AIWeapon>().UseWeapon();
isPreparingToShoot =false;
}
IEnumerator Idle()
{
EnemyAnim.SetBool("PrepareAttack", false);
yield return new WaitUntil(() => Vector3.Distance(PlayerTr.transform.position, transform.position) < 20 || isAlerted);
StartCoroutine(RunToTarget());
}
IEnumerator RunToTarget()
{
aIPatrolBehavior.enabled =false;
if(navAgent.isOnNavMesh) { // save from error apperng
navAgent.isStopped = false;
}
EnemyAnim.SetTrigger("Attack");
while (Vector3.Distance(PlayerTr.transform.position, transform.position) > AttackRange - 0.5f)
{
if(navAgent.isOnNavMesh) { // save from error apperng
navAgent.SetDestination(PlayerTr.position);
}
// navAgent.SetDestination(PlayerTr.position);
EnemyAnim.SetFloat("MovmentSpeed", 1, 0.3f, Time.deltaTime);
yield return null;
}
StartCoroutine(Attack());
}
IEnumerator Attack()
{
EnemyAnim.SetBool("PrepareAttack", true);
navAgent.isStopped = true;
while (Vector3.Distance(PlayerTr.position, transform.position) < AttackRange)
{
EnemyAnim.SetTrigger("Attack");
float t = 0.5f;
while (t > 0)
{
Vector3 rotation = Vector3.RotateTowards(transform.forward, PlayerTr.position - transform.position, 5f * Time.deltaTime, 1f);
transform.forward = rotation;
t -= Time.deltaTime;
yield return null;
}
yield return null;
}
EnemyAnim.SetBool("PrepareAttack", false);
StartCoroutine(RunToTarget());
}
float DistanceToPlayer(){
return Vector3.Distance(transform.position,PlayerTr.position);
}
public void DoDamage(float damage)
{
Alert();
if (!showingHealthBar)
{
showingHealthBar = true;
StartCoroutine(ShowHealthBar());
}
Health -= damage;
Debug.Log("Health: " + Health + " of: " + MaxHealth);
Healthbar.value = Health;
if (Health <= 0)
{
StopAllCoroutines();
if(navAgent.isOnNavMesh) { // save from error apperng
navAgent.isStopped = true;
}
if (alive)
{
alive = true; // does this make sense?
StartCoroutine(Death());
}
}
}
I have tried searching through Google to find any tutorials, but without success. Does anyone have any ideas?
if the weapons placed on constant places all over the map, you can make the enemy stop patrolling or chasing the player when his ammo == 0 by a Boolean then use MoveTowrds() the weapon.
and u can include some way to calculate the distance between the enemy's position and all the weapons on the array, then it head for the closest.
you will use an array of vectors to store the locations of weapons.
now its your turn to try.
so i've been working on some code for a game in Unity and i am using the Input.GetMouseButtonDown(1) function. However, it only works the first time i press the left click in the game and no other times after that. The code for the player controller where it's used is below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
public float speed;
public Transform enemy;
public Transform shot;
public GameObject shotObj;
public Text scoreT;
public Text timeT;
public Text roundT;
public float health;
public float damageTaken;
public Vector3 lookPoint;
public float shotSpeed;
private Camera mainCamera;
private int round = 1;
private int tempRound = 0;
private float time = 300;
private bool win = false;
private bool allowShoot;
private EnemyController enemyScript;
private ShotController shotScript;
private bool tempImune = false;
private int targetTime;
private int score = 0;
private int defeatedEnemy = 0;
private GameObject enemyObj;
//coroutine
IEnumerator Pause(float timE)
{
allowShoot = false;
//time since the object was created
float start = Time.realtimeSinceStartup;
//sets the game to slow down to 0 movement
Time.timeScale = 0.0f;
//loops until start up time is less than start time + pause time
while (Time.realtimeSinceStartup < start + timE)
{
//returns null from the subroutine and restarts the subroutine at this point after null (0) time has passed
yield return null;
}
//sets the gamne to be running at normal speed
Time.timeScale = 1.0f;
allowShoot = true;
if (timE == 5.0f)
{
roundT.gameObject.SetActive(false);
}
}
void Start () {
//center mouse
Cursor.lockState = CursorLockMode.Locked;
Cursor.lockState = CursorLockMode.None;
//set camera to be the camera in the scene (should only ever be one camera in the scene)
mainCamera = FindObjectOfType<Camera>();
//set default text values
scoreT.text = "Score: 000000";
timeT.text = "Time Left: 600";
roundT.text = "Round: " + round;
//pause game before first round begins
StartCoroutine(Pause(5.0f));
}
void Update () {
//looka at mouse script
Ray cameraRay = mainCamera.ScreenPointToRay(Input.mousePosition);
Plane ground = new Plane(Vector3.up, Vector3.zero);
float rayLength;
if (ground.Raycast(cameraRay, out rayLength))
{
lookPoint = cameraRay.GetPoint(rayLength);
transform.LookAt(new Vector3(lookPoint.x, transform.position.y, lookPoint.z));
}
//enemy spawner check and win criteria check
if (defeatedEnemy != 45)
{
if (round != tempRound)
{
spawnEnemy();
roundT.gameObject.SetActive(true);
if (round == 5)
{
roundT.text = "Round: " + round + "(Final Round)";
}
else
{
roundT.text = "Round: " + round;
}
StartCoroutine(Pause(5.0f));
}
}
else
{
win = true;
}
//timer and win check
if (health == 0f)
{
win = true;
}
if (!win)
{
time -= Time.deltaTime;
timeT.text = "Time Left: " + time;
}
else
{
if (health == 0f)
{
roundT.gameObject.SetActive(true);
int finalScore = Mathf.RoundToInt(score * ((time / 2) / 10));
roundT.text = "To Bad, You Loose! Score = " + finalScore;
Debug.Log(finalScore);
StartCoroutine(Pause(99999f));
}
else
{
roundT.gameObject.SetActive(true);
int finalScore = Mathf.RoundToInt(score * ((time / 2) / 10));
roundT.text = "Congratulations! Score = " + finalScore;
Debug.Log(finalScore);
}
}
//movement controlls
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
{
transform.Translate(new Vector3(0.0f, 0.0f, speed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
{
transform.Translate(new Vector3(-speed * Time.deltaTime, 0.0f, 0.0f));
}
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
{
transform.Translate(new Vector3(0.0f, 0.0f, -speed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
{
transform.Translate(new Vector3(speed * Time.deltaTime, 0.0f, 0.0f));
}
//shoot controll
if (allowShoot)
{
Debug.Log("shot allowed");
if (Input.GetMouseButtonDown(0))
{
//var spawnShot = Instantiate(shot, this.transform.position + new Vector3(0.0f, 0.0f, 0.5f), this.transform.rotation);
//shotScript = shotObj.GetComponent<ShotController>();
//if (shotScript.enemy)
//{
// Debug.Log("enemy found");
// enemyScript = shotScript.enemy.GetComponent<EnemyController>();
// if(enemyScript.health <= 0.0f)
// {
// score += 20;
// defeatedEnemy += 1;
// scoreT.text = "Score: " + score;
// Debug.Log("enemy killed : " + defeatedEnemy);
// }
//}
Debug.Log("mouseDown");
int layermask = 1 << 8;
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, Mathf.Infinity, layermask))
{
enemyObj = hit.transform.gameObject;
enemyScript = enemyObj.GetComponent<EnemyController>();
Debug.Log("hit");
//hit.transform.SendMessage("HitByRay");
if (enemyScript.health == 0f)
{
Destroy(hit.transform.gameObject);
score += 20;
defeatedEnemy += 1;
scoreT.text = "Score: " + score;
Debug.Log("enemy killed : " + defeatedEnemy);
}
}
}
}
//enemy existance check
if (GameObject.Find("Enemy(Clone)") == null)
{
round = round + 1;
}
if (tempImune)
{
if (Mathf.RoundToInt(time) == targetTime)
{
tempImune = false;
}
}
}
void spawnEnemy()
{
tempRound = round;
for (int i = 1; i <= round * 3; i++)
{
var spawnEnemy = Instantiate(enemy, new Vector3(Random.Range(-14.5f, 14.5f), 0.25f, Random.Range(-6f, 6f)), Quaternion.identity);
}
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "Enemy")
{
if (!tempImune)
{
health = health - damageTaken;
Debug.Log(health);
tempImune = true;
targetTime = Mathf.RoundToInt(time) - 1;
}
}
}
}
Any help with this would be greatly appreciated as it's for a school project. Thanks.
You need to call this function from the Update function, since the state gets reset each frame. It will not return true until the user has released the mouse button and pressed it again. button values are 0 for the primary button (often the left button), 1 for secondary button, and 2 for the middle button
using UnityEngine;
using System.Collections;
public class ClassName : MonoBehaviour
{
void Update()
{
if (Input.GetMouseButtonDown(0))
Debug.Log("Pressed primary button.");
if (Input.GetMouseButtonDown(1))
Debug.Log("Pressed secondary button.");
if (Input.GetMouseButtonDown(2))
Debug.Log("Pressed middle click.");
}
}
I am trying to develop an AI that works with photon networking system, in unity engine. It should be fairly simple: it runs to a random player till it reaches 5 units distance between him and player, then it walk at a slightly slower speed till it reaches the front of the player. Then he attacks. So far so good, but sometimes, the AI get stuck right when it reaches 5 units distance between him and the player. I tried several fixes from the internet, but nothing worked.
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(PhotonView))]
[RequireComponent(typeof(PhotonTransformView))]
public class EnemyAI : Photon.MonoBehaviour {
NavMeshAgent agent;
Animator anim;
PlayerController target;
[Header("Base settings")]
[SerializeField]
float health = 100f, damage, timeBetweenAttacks = 5f;
[Space]
[Header("Enemy Ragdoll")]
[SerializeField]
GameObject ragdoll;
AudioSource emotAud, stepAud;
[Space]
[SerializeField]
[Header("Audio")]
List<AudioClip> attackingAuds;
[Space]
[Header("Sunete pasi")]
[SerializeField]
List<AudioClip> stepAuds;
[Space]
[Header("Alte optiuni")]
[SerializeField]
float distantaLaCareIncepeSaMearga = 5f, walkSpeed = .5f, runSpeed = 3.5f;
bool dead, walking;
PhotonView killer;
float nextAttackTime;
// Use this for initialization
void Start () {
emotAud = gameObject.AddComponent<AudioSource>();
stepAud = gameObject.AddComponent<AudioSource>();
emotAud.spatialBlend = 1;
emotAud.maxDistance = 7;
stepAud.spatialBlend = 1;
stepAud.maxDistance = 7;
emotAud.playOnAwake = false;
stepAud.playOnAwake = false;
dead = false;
target = null;
agent = GetComponent<NavMeshAgent>();
anim = GetComponent<Animator>();
killer = null;
}
// Update is called once per frame
void Update () {
if (photonView.isMine)
{
if (walking)
{
agent.speed = walkSpeed;
}
else
{
agent.speed = runSpeed;
}
if (health <= 0)
{
if (!dead)
{
dead = true;
photonView.RPC("die", PhotonTargets.AllBuffered);
}
}
if (!target)
{
if (!PhotonNetwork.offlineMode)
{
nextAttackTime = (float)PhotonNetwork.room.CustomProperties["remainTime"];
}
else
{
nextAttackTime = 0f;
}
PlayerController[] controllers = FindObjectsOfType<PlayerController>();
int randCh = Random.Range(0, controllers.Length);
if (controllers.Length > 0)
{
target = controllers[randCh];
}
anim.SetFloat("move", 0);
}
else
{
if (Vector3.Distance(transform.position, target.gameObject.transform.position) > 1.8f)
{
if (Vector3.Distance(transform.position, target.gameObject.transform.position) > distantaLaCareIncepeSaMearga)
{
walking = false;
}
else
{
walking = true;
}
anim.SetBool("walking", walking);
anim.SetFloat("move", 1);
//print("Active: " + agent.isActiveAndEnabled + " Pend: " + agent.pathPending + " Has path: " + agent.hasPath);
if (agent.isActiveAndEnabled)
{
if (!agent.pathPending)
{
agent.SetDestination(target.gameObject.transform.position - transform.forward * 1.2f);
}
}
}
else
{
if (!PhotonNetwork.offlineMode)
{
if (nextAttackTime >= (float)PhotonNetwork.room.CustomProperties["remainTime"])
{
anim.SetTrigger("attack");
nextAttackTime -= timeBetweenAttacks;
}
else
{
anim.SetFloat("move", 0);
}
}
else
{
if (nextAttackTime <= 0f)
{
anim.SetTrigger("attack");
nextAttackTime += timeBetweenAttacks;
}
else
{
nextAttackTime -= Time.deltaTime;
anim.SetFloat("move", 0);
}
}
}
}
}
}
void OnDrawGizmosSelected()
{
if (target)
{
Gizmos.color = Color.blue;
Gizmos.DrawSphere(agent.destination, 1);
}
}
[PunRPC]
void die()
{
if (killer)
{
killer.gameObject.GetComponent<PlayerController>().kill();
}
if (attackingAuds.Count > 0)
{
emotAud.clip = attackingAuds[Random.Range(0, attackingAuds.Count - 1)];
emotAud.Play();
}
gameObject.GetComponent<CapsuleCollider>().enabled = false;
Instantiate(ragdoll, transform.position, transform.rotation);
Destroy(this.gameObject);
}
public void attack()
{
if (target && target.health >= 0)
{
if (Vector3.Distance(target.gameObject.transform.position, transform.position) <= 2f)
{
target.doDamage(damage);
if (target.health <= 0)
{
target.photonView.RPC("die", PhotonTargets.All, true);
}
}
}
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag.Contains("Bullet"))
{
killer = col.gameObject.GetComponent<Magic_Bullet>().owner;
target = killer.gameObject.GetComponent<PlayerController>();
photonView.RPC("takeDamage", PhotonTargets.AllBuffered, col.gameObject.GetComponent<Magic_Bullet>().damage);
PhotonNetwork.Destroy(col.gameObject);
}
}
[PunRPC]
void takeDamage(float dmg)
{
health -= dmg;
}
public void step()
{
stepAud.clip = stepAuds[Random.Range(0, stepAuds.Count - 1)];
stepAud.Play();
}
}
What am I doing wrong?
Well there's a hell of if else in your update function which just gives a headache to all of us,
Instead, try implementing a simple FSM using scriptableobject (as unity official tutorials ) or Coroutines which requires hard coding and is not recommended.
https://unity3d.com/learn/tutorials/topics/navigation/finite-state-ai-delegate-pattern
What i'm trying to do is once the random flag is true move the player between the waypoints randomly.
but just calling the random method is not enough.
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class Waypoints : MonoBehaviour
{
public GameObject[] waypoints;
public Transform target;
public float moveSpeed = 10f;
public float slowDownSpeed = 3f;
public float reverseSlowDownSpeed = 3f;
public float rotationSpeed = 1f;
private int targetsIndex = 0;
private Vector3 originalPosition;
private GameObject[] players;
public Transform reverseTarget;
private int reverseTargetsIndex = 0;
private Vector3 reverseOriginalPosition;
public bool random = false;
// Use this for initialization
void Start()
{
waypoints = GameObject.FindGameObjectsWithTag("Blocks");
players = GameObject.FindGameObjectsWithTag("Player");
originalPosition = players[0].transform.localPosition;
}
// Update is called once per frame
void Update()
{
if (random == true)
{
RandomWayPointsAI();
}
else
{
WayPointsAI();
}
}
private void WayPointsAI()
{
if (targetsIndex == waypoints.Length)
targetsIndex = 0;
target = waypoints[targetsIndex].transform;
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[0].transform.localPosition += players[0].transform.forward * slowDownSpeed * Time.deltaTime;
}
else
{
players[0].transform.localPosition += players[0].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < target.transform.localScale.magnitude)
{
targetsIndex++;
}
}
private void ReverseWayPointsAI()
{
if (reverseTargetsIndex == 0)
reverseTargetsIndex = waypoints.Length - 1;
reverseTarget = waypoints[reverseTargetsIndex].transform;
float distance = Vector3.Distance(players[1].transform.position, reverseTarget.transform.position);
players[1].transform.rotation = Quaternion.Slerp(players[1].transform.rotation, Quaternion.LookRotation(reverseTarget.position - players[1].transform.position), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[1].transform.position += players[1].transform.forward * reverseSlowDownSpeed * Time.deltaTime;
}
else
{
players[1].transform.position += players[1].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < reverseTarget.transform.localScale.magnitude)
{
reverseTargetsIndex--;
}
}
void RandomWayPointsAI()
{
if (random == true)
{
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
}
}
void DrawLinesInScene()
{
// draw lines between each checkpoint //
for (int i = 0; i < waypoints.Length - 1; i++)
{
Debug.DrawLine(waypoints[i].transform.position, waypoints[i + 1].transform.position, Color.blue);
}
// draw a line between the original transform start position
// and the current transform position //
Debug.DrawLine(originalPosition, players[0].transform.position, Color.red);
Debug.DrawLine(reverseOriginalPosition, players[1].transform.position, Color.red);
// draw a line between current transform position and the next waypoint target
// each time reached a waypoint.
if (target != null)
Debug.DrawLine(target.transform.position, players[0].transform.position, Color.green);
if (reverseTarget != null)
Debug.DrawLine(reverseTarget.transform.position, players[1].transform.position, Color.green);
}
void AddColliderToWaypoints()
{
foreach (GameObject go in waypoints)
{
SphereCollider sc = go.AddComponent<SphereCollider>() as SphereCollider;
sc.isTrigger = true;
}
}
}
Inside the Update i'm checking if random is true then calling the RandomWayPointsAI(); but it's not moving the player it's just keep picking up each frame a new random waypoint but that's it.
void Update()
{
if (random == true)
{
RandomWayPointsAI();
}
else
{
WayPointsAI();
}
}
Here is your answer. First you are not writing the movement code in the random function and you are expecting it to move.
bool getNextRandom = true;
void RandomWayPointsAI()
{
if (random == true && getNextRandom)
{
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
getNextRandom = false;
}
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[0].transform.localPosition += players[0].transform.forward * slowDownSpeed * Time.deltaTime;
}
else
{
players[0].transform.localPosition += players[0].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < target.transform.localScale.magnitude)
{
getNextRandom = true;
}
}
Further you can imporve the solution by moving the movement code to another function which will give you better control
public GameObject[] waypoints;
public Transform target;
public float moveSpeed = 10f;
public float slowDownSpeed = 3f;
public float reverseSlowDownSpeed = 3f;
public float rotationSpeed = 1f;
private int targetsIndex = 0;
private Vector3 originalPosition;
private GameObject[] players;
public Transform reverseTarget;
private int reverseTargetsIndex = 0;
private Vector3 reverseOriginalPosition;
public bool random = false;
public bool getNextRandom = true;
// Use this for initialization
void Start()
{
waypoints = GameObject.FindGameObjectsWithTag("Blocks");
players = GameObject.FindGameObjectsWithTag("Player");
originalPosition = players[0].transform.localPosition;
}
// Update is called once per frame
void Update()
{
if (random == true)
{
RandomWayPointsAI();
}
else
{
WayPointsAI();
}
}
private void WayPointsAI()
{
if (targetsIndex == waypoints.Length)
targetsIndex = 0;
target = waypoints[targetsIndex].transform;
if (MovePlayer())
targetsIndex++;
}
private void ReverseWayPointsAI()
{
if (reverseTargetsIndex == 0)
reverseTargetsIndex = waypoints.Length - 1;
reverseTarget = waypoints[reverseTargetsIndex].transform;
if (MovePlayer())
reverseTargetsIndex--;
}
void RandomWayPointsAI()
{
if (random == true && getNextRandom)
{
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
getNextRandom = false;
}
getNextRandom = MovePlayer();
}
bool MovePlayer()
{
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
players[0].transform.localPosition += players[0].transform.forward * slowDownSpeed * Time.deltaTime;
}
else
{
players[0].transform.localPosition += players[0].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < target.transform.localScale.magnitude)
return true;
else
return false;
}
void DrawLinesInScene()
{
// draw lines between each checkpoint //
for (int i = 0; i < waypoints.Length - 1; i++)
{
Debug.DrawLine(waypoints[i].transform.position, waypoints[i + 1].transform.position, Color.blue);
}
// draw a line between the original transform start position
// and the current transform position //
Debug.DrawLine(originalPosition, players[0].transform.position, Color.red);
Debug.DrawLine(reverseOriginalPosition, players[1].transform.position, Color.red);
// draw a line between current transform position and the next waypoint target
// each time reached a waypoint.
if (target != null)
Debug.DrawLine(target.transform.position, players[0].transform.position, Color.green);
if (reverseTarget != null)
Debug.DrawLine(reverseTarget.transform.position, players[1].transform.position, Color.green);
}
void AddColliderToWaypoints()
{
foreach (GameObject go in waypoints)
{
SphereCollider sc = go.AddComponent<SphereCollider>() as SphereCollider;
sc.isTrigger = true;
}
}
If you look at your RandomWayPointsAI() function, it only defines the index and the target but don't have any code below it to move the player.
private void WayPointsAI()
{
if (targetsIndex == waypoints.Length)
targetsIndex = 0;
target = waypoints[targetsIndex].transform;
float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);
void RandomWayPointsAI()
{
//No need to check if random is true anymore, you already checked when you run this function
int index = UnityEngine.Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
//float distance = Vector3.Distance(players[0].transform.position, target.transform.position);
//players[0].transform.localRotation = Quaternion.Slerp(players[0].transform.localRotation, Quaternion.LookRotation(target.position - players[0].transform.localPosition), rotationSpeed * Time.deltaTime);**
}
https://gyazo.com/0a29918f513316fc4143a5ff76095bd3
This is how it looks visually.
That's my shooting weapon code:
public class Weapon : MonoBehaviour {
public float fireRate = 0;
public float maxDamage = 10;
public LayerMask whatToHit ;
public Transform BulletTrailPrefab;
public Transform MuzzleFlashPrefab;
public Transform HitPrefab;
float timeToSpawnEffect = 0;
public float effectSpawnRate = 10;
float timeToFire = 0;
Transform firePoint;
// Use this for initialization
void Awake () {
firePoint = transform.FindChild("FirePoint");
if(firePoint == null)
{
Debug.LogError("No FirePoint");
}
}
// Update is called once per frame
void Update () {
if(fireRate == 0)
{
if (Input.GetButtonDown("Fire1"))
{
Shoot();
}
}else
{
if(Input.GetButton("Fire1") && Time.time > timeToFire)
{
timeToFire = Time.time + 1 / fireRate;
Shoot();
}
}
}
void Shoot()
{
Vector2 mousePosition = new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
Vector2 firePointPosition = new Vector2(firePoint.position.x, firePoint.position.y);
RaycastHit2D hit = Physics2D.Raycast(firePointPosition,mousePosition - firePointPosition,100,whatToHit);
Debug.DrawLine(firePointPosition, (mousePosition - firePointPosition) * 100,Color.cyan);
if(hit.collider != null)
{
Debug.DrawLine(firePointPosition, hit.point, Color.red);
Enemy enemy = hit.collider.GetComponent<Enemy>();
if(enemy != null)
{
enemy.DamageEnemy(Random.Range(maxDamage/2,maxDamage));
// Debug.Log("we hit" + hit.collider.name + " and did: " + maxDamage + " damage");
}
}
if (Time.time >= timeToSpawnEffect)
{
Vector3 hitPos;
Vector3 hitNormal;
if (hit.collider == null)
{
hitPos = (mousePosition - firePointPosition) * 30;
hitNormal = new Vector3(9999, 9999, 9999);
}
else
{
hitPos = hit.point;
hitNormal = hit.normal;
}
Effect(hitPos,hitNormal);
timeToSpawnEffect = Time.time + 1 / effectSpawnRate;
}
}
void Effect(Vector3 hitPos, Vector3 hitNormal)
{
Transform trail = Instantiate(BulletTrailPrefab,firePoint.position,firePoint.rotation) as Transform;
LineRenderer lr = trail.GetComponent<LineRenderer>();
if(lr != null)
{
// Set positions
lr.SetPosition(0, firePoint.position);
lr.SetPosition(1, hitPos);
}
Destroy(trail.gameObject, 0.035f);
if (hitNormal != new Vector3(9999, 9999, 9999))
{
Transform hitParticle = Instantiate(HitPrefab, hitPos, Quaternion.FromToRotation(Vector3.right,hitNormal)) as Transform;
hitParticle.parent = transform.parent;
Destroy(hitParticle.gameObject, 0.3f);
}
Transform clone = Instantiate(MuzzleFlashPrefab, firePoint.position, firePoint.rotation);
clone.parent = firePoint;
float size = Random.Range(0.3f, 0.5f);
clone.localScale = new Vector3(size, size, size);
Destroy(clone.gameObject, 0.02f);
}
}
I've been trying to figure it out what's wrong for hours now. Checked the code just too many times, don't know how to google this problem. Just can't understand why it's hitting everything except that spaceship..
Don't know what other information you might need so tell me if you need something more.