Hello everyone I have a question. I have 2 script files on Unity.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Rendering.Universal;
public class CycleFinal : MonoBehaviour
{
//Lights
public Light2D GlobLight;
public Light2D SptLight;
//Displays
public Text timeDisplay;
public Text moveDisplay;
public Text phaseDisplay;
//Others
[SerializeField]
public float cdTimer = 20f;
public float moveCount = 20f;
void Start()
{
timeDisplay.GetComponent<Text>();
moveDisplay.GetComponent<Text>();
phaseDisplay.GetComponent<Text>();
moveCount = 0f;
DayTime();
}
void Update()
{
cdTimer -= Time.deltaTime;
if(cdTimer <0){
NightTime();
}else if(moveCount <0){
DayTime();
}
timeDisplay.text = "Day Time left: " + Mathf.Round(cdTimer);
moveDisplay.text = "Movement left: " + Mathf.Round(moveCount);
}
public void DayTime(){
phaseDisplay.text = "Day";
SptLight.intensity = 0;
GlobLight.intensity = 1;
moveCount = 0;
}
public void NightTime(){
phaseDisplay.text = "Night";
SptLight.intensity = 1;
GlobLight.intensity = 0;
moveCount = 20;
cdTimer = 0;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class PlayerController : MonoBehaviour
{
public CycleFinal script;
private PlayerMovement controls;
[SerializeField]
private Tilemap groundTilemap;
[SerializeField]
private Tilemap collisionTilemap;
private void Awake() {
controls = new PlayerMovement();
}
private void OnEnable() {
controls.Enable();
}
private void OnDisable() {
controls.Disable();
}
void Start()
{
controls.Main.Movement.performed += ctx => Move(ctx.ReadValue<Vector2>());
}
private void Move(Vector2 direction){
if(CanMove(direction))
transform.position += (Vector3)direction;
}
private bool CanMove(Vector2 direction){
Vector3Int gridPosition = groundTilemap.WorldToCell(transform.position + (Vector3)direction);
if(!groundTilemap.HasTile(gridPosition) || collisionTilemap.HasTile(gridPosition) || script.moveCount <= 0)
return false;
else
return true;
}
}
I am trying to decrease moveCount variable on every move my character made. (I'm planing to do this thing on PlayerController script Move function.) I accomplished this while moveCount variable is a variable outside of the NightTime function but when I move that moveCount variable in to the NightTime function I couldn't change its value. How can I do that?
Also main thing I want to do with those 2 script is the player will have x seconds of day time and x moves on nighttime when x seconds ends the game turns into night time and when x moves ends the game turns into day time.
Related
I am trying to create a multiplayer TPS where I instantiate a bullet locally (in my editor) and apply force to it. Once it hits other player I would want to call that players TakeDamage RPC.
Sadly I am encountering this weird error message that I can't fix (already taking me days).
my projectile script:
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Arrow : MonoBehaviour
{
[SerializeField] float timeToDestroy;
[SerializeField] ParticleSystem hitEffect;
[SerializeField] TrailRenderer trailRenderer;
float timer;
private Rigidbody rb;
private Collider col;
private void Awake()
{
rb = GetComponent<Rigidbody>();
col = GetComponent<Collider>();
}
private void Update()
{
timer += Time.deltaTime;
if (timer > timeToDestroy) Destroy(gameObject);
}
private void OnCollisionEnter(Collision collision)
{
rb.isKinematic = true;
rb.velocity = Vector3.zero;
trailRenderer.enabled = false;
ShowHitEffect(collision.GetContact(0));
col.enabled = false;
if (collision.gameObject.CompareTag("Player"))
{
rb.isKinematic = true;
rb.velocity = Vector3.zero;
trailRenderer.enabled = false;
PhotonView pv = collision.gameObject.GetPhotonView();
Debug.Log("hit " + pv.Controller.NickName);
pv.RPC("DealDamage", RpcTarget.All, PhotonNetwork.LocalPlayer.NickName, .5f, PhotonNetwork.LocalPlayer.ActorNumber);
}
Destroy(gameObject, 2f);
}
private void ShowHitEffect(ContactPoint cp)
{
hitEffect.transform.position = cp.point;
hitEffect.transform.forward = cp.normal;
hitEffect.Emit(1);
}
}
weapon controller script
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponController : MonoBehaviourPunCallbacks
{
[Header("Fire Rate")]
[SerializeField] float fireRate;
float fireRateTimer;
[SerializeField] bool semiAuto;
[Header("Bullet Property")]
[SerializeField] GameObject bullet;
[SerializeField] Transform barrelPos;
[SerializeField] float bulletVelocity;
[SerializeField] byte bulletPerShot;
public AimController aim;
[SerializeField] AudioClip gunshot;
public AudioSource audioSource;
public WeaponAmmo ammo;
public ParticleSystem muzzleFlash;
public ParticleSystem hitEffect;
// Start is called before the first frame update
void Start()
{
fireRateTimer = fireRate;
}
private void Update()
{
if (!photonView.IsMine) return;
if (ShouldFire()) Fire();
}
bool ShouldFire()
{
fireRateTimer += Time.deltaTime;
if (fireRateTimer < fireRate) return false;
if (ammo.currentAmmo == 0) return false;
if (semiAuto && Input.GetKeyDown(KeyCode.Mouse0)) return true;
if (!semiAuto && Input.GetKey(KeyCode.Mouse0)) return true;
return false;
}
[PunRPC]
private void EmitMuzzleFlash()
{
muzzleFlash.Emit(1);
}
void Fire()
{
fireRateTimer = 0;
barrelPos.LookAt(aim.actualAimPos);
audioSource.PlayOneShot(gunshot);
EmitMuzzleFlash();
//photonView.RPC("EmitMuzzleFlash", RpcTarget.All);
ammo.currentAmmo--;
for (int i = 0; i < bulletPerShot; i++)
{
GameObject currentBullet = Instantiate(bullet, barrelPos.position, barrelPos.rotation);
Rigidbody rigidbody = currentBullet.GetComponent<Rigidbody>();
rigidbody.AddForce(barrelPos.forward * bulletVelocity, ForceMode.Impulse);
// Projectile Instantiate
/*{
GameObject currentProjectile = (GameObject)PhotonNetwork.Instantiate(bullet.name, barrelPos.position, barrelPos.rotation);
Rigidbody rb = currentProjectile.GetComponent<Rigidbody>();
rb.AddForce(barrelPos.forward * bulletVelocity, ForceMode.Impulse);
}*/
}
}
}
player controller script (where rpc is located)
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviourPunCallbacks
{
private PlayerStats stats = new PlayerStats();
void Start()
{
if (photonView.IsMine)
{
UIController.instance.healthSlider.maxValue = stats.maxHealth;
UIController.instance.healthSlider.value = stats.GetCurrentHealth();
}
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
FocusWindows();
}
void FocusWindows()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
Cursor.lockState = CursorLockMode.None;
}
else if (Cursor.lockState == CursorLockMode.None)
{
if (Input.GetMouseButton(0))
{
Cursor.lockState = CursorLockMode.Locked;
}
}
}
#region
[PunRPC]
public void DealDamage(string damager, float damageAmount, int actor)
{
Debug.Log("called rpc deal damage");
Debug.Log("damager " + damager + " damageAmount " + damageAmount + " actor " + actor);
TakeDamage(damager, damageAmount, actor);
}
public void TakeDamage(string damager, float damageAmount, int actor)
{
if (photonView.IsMine)
{
stats.ReduceHealth(damageAmount);
if (stats.GetCurrentHealth() == 0)
{
PlayerSpawner.Instance.Die(damager);
MatchManager.instance.UpdateStatSend(actor, 0, 1);
}
UIController.instance.healthSlider.value = stats.GetCurrentHealth();
}
}
#endregion
}
Projectile Prefab(resource)
enter image description here
Player prefab
enter image description here
Weird thing is if I go with "Instantiate Arrow in the network" the rpc is getting called. But this is not ideal since it will because it will send the transform of the projectile every time it is flying. So I just want to check in the local (arrow with no photonView) if it hits an enemy then call the rpc of that enemy to make him take damage and possibly display a fake project coming from the damager. If my approach is naive / wrong please tell me a better approach please.
I transfered the rpc call on the same script where the photonView is located as mentioned by #derHugo. I think the main problem was my understanding of RPC. I thought rpc is like a public method where you can call it outside. I think I need to reread the documentations about rpc and raise events.
I am very new to programming.. I tried to make a endless runner with unity and I am at the point now that I want to make platforms to spawn automatically. I followed a tutorial but whenever I reach the end no new platforms are being spawned ):
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TESTGAMEMANAGER : MonoBehaviour
{
private const float PLAYER_DISTANCE_SPAWN_LEVEL_PART = 50f;
[SerializeField] private Transform levelPart_Start;
[SerializeField] private List<Transform> levelPartList;
[SerializeField] private PlayerScript player;
private Vector3 lastEndPosition;
private void Awake()
{
lastEndPosition = levelPart_Start.Find("EndPoint").position;
int startingSpawnLevelParts = 5;
for (int i = 0; i < startingSpawnLevelParts; i++)
{
SpawnLevelPart();
}
}
private void Update()
{
if (Vector3.Distance(player.transform.position(), lastEndPosition) < PLAYER_DISTANCE_SPAWN_LEVEL_PART)
{
// Spawn another level part
SpawnLevelPart();
}
}
private void SpawnLevelPart()
{
Transform chosenLevelPart = levelPartList[Random.Range(0, levelPartList.Count)];
Transform lastLevelPartTransform = SpawnLevelPart(chosenLevelPart, lastEndPosition);
lastEndPosition = lastLevelPartTransform.Find("EndPoint").position;
}
private Transform SpawnLevelPart(Transform levelPart, Vector3 spawnPosition)
{
Transform levelPartTransform = Instantiate(levelPart, spawnPosition, Quaternion.identity);
return levelPartTransform;
}
}
It seems like that only at the start there are platforms but after some time I reach the end and fall down );
Anyone know how to fix that?
Unity Picture with problem
I am making a script that allows the payer to move and jump. Moving with the WASD keys is fine but when I press the space bar to jump, but the console says NaN and the gravity in the game stops working I've looked at my player motor script and my input manager script, but I can't find any errors.
player motor script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMotor : MonoBehaviour
{
private CharacterController controller;
private Vector3 PlayerVelocity;
private bool isGrounded;
public float speed = 5f;
public float gravity = -9.8f;
public float jumpHeight = -3f;
// Start is called before the first frame update
void Start()
{
controller = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
isGrounded = controller.isGrounded;
}
public void ProcessMove(Vector2 input)
{
Vector3 moveDirection = Vector3.zero;
moveDirection.x = input.x;
moveDirection.z = input.y;
controller.Move(transform.TransformDirection(moveDirection) * speed * Time.deltaTime);
PlayerVelocity.y += gravity * Time.deltaTime;
if (isGrounded && PlayerVelocity.y < 0)
PlayerVelocity.y = -2f;
controller.Move(PlayerVelocity * Time.deltaTime);
Debug.Log(PlayerVelocity.y);
}
public void Jump()
{
if (isGrounded)
{
PlayerVelocity.y = Mathf.Sqrt(jumpHeight * -3.0f * gravity);
}
}
}
input manager script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class InputManager : MonoBehaviour
{
private PlayerInput playerInput;
private PlayerInput.OnFootActions onFoot;
private PlayerMotor motor;
// Start is called before the first frame update
void Awake()
{
playerInput = new PlayerInput();
onFoot = playerInput.OnFoot;
motor = GetComponent<PlayerMotor>();
onFoot.Jump.performed += ctx => motor.Jump();
}
// Update is called once per frame
void FixedUpdate()
{
// tell the playermotor to move using the value from our movement action
motor.ProcessMove(onFoot.Movement.ReadValue<Vector2>());
}
private void OnEnable()
{
onFoot.Enable();
}
private void OnDisable()
{
onFoot.Disable();
}
}
In this line it seems you are trying to get the square root of a negative number? PlayerVelocity.y = Mathf.Sqrt(jumpHeight * -3.0f * gravity);
Gravity and jumpheight are negative, multiplied with -3.0 that results in a negative number.
A quick test in Unity reveals that Mathf.Sqrt doesn't throw an error on negatives and instead returns NaN.
I am making a multiplayer MMO with unity and I am stuck on syncing up enemy spawning between clients. Basically the enemies spawn as intended, but only on the user that spawned them. Here is my code (Sorry it is a bit long, just wanted to include any information that could be relevant, as the is my first time with networking):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
[System.Serializable]
public class EnemySpawn {
public GameObject prefab;
public int difficulty;
public int rarity;
[HideInInspector()]
public GameObject instance;
}
public class EnemySpawner : NetworkBehaviour {
public EnemySpawn[] enemys;
public int maxDiff = 8;
public int spawnDistMin = 15;
public int spawnDistMax = 35;
public int spawnLvlDist = 30;
private int diffOnScreen;
private EnemySpawn enemyToSpawn;
public List<EnemySpawn> enemysOnScreen = new List<EnemySpawn>();
void Start() {
StartCoroutine (Spawn());
}
void Update() {
List<EnemySpawn> newEnemysOnScreen = new List<EnemySpawn>();
foreach(EnemySpawn c in enemysOnScreen) {
if (c.instance == null) {
diffOnScreen -= c.difficulty;
} else {
newEnemysOnScreen.Add (c);
}
}
enemysOnScreen = newEnemysOnScreen;
}
//IMPORTANT PART!!! \/\/\/
[Command]
void CmdSpawn(Vector3 pos) {
GameObject spawning = Instantiate (enemyToSpawn.prefab, pos, Quaternion.identity);
NetworkServer.Spawn (spawning);
diffOnScreen += enemyToSpawn.difficulty;
enemysOnScreen.Insert (0,enemyToSpawn);
enemysOnScreen [0].instance = spawning;
spawning.GetComponent<MonsterMain>().lvl = Mathf.RoundToInt(spawning.transform.position.magnitude / spawnLvlDist);
}
IEnumerator Spawn() {
while (true) {
int n = 0;
while (n != 1) {
enemyToSpawn = enemys [Random.Range (0, enemys.Length)];
n = Random.Range (1, enemyToSpawn.rarity);
}
while (maxDiff - diffOnScreen <= enemyToSpawn.difficulty) {
yield return null;
}
yield return null;
Transform player = Player.localPlayer.transform;
Vector2 randomOffset = Random.insideUnitCircle.normalized * Random.Range (spawnDistMin, spawnDistMax);
CmdSpawn(player.position + new Vector3(randomOffset.x,randomOffset.y,0));
}
}
}
I am using Unity 2017.1.3.3p3, and I am building this to IOS. It is a 2d game and I am using unity's build in networking system. Again everything works except that the enemies only spawn on one screen. I am connecting one phone to the editor. Any help is appreciated. thank you!
I am currently building my first multiplayer game in unity and having a little bit of an issue changing/transmitting the players direction over the network.
My current player controls class is this:
using UnityEngine;
using System.Collections;
public class playerControls : MonoBehaviour {
#region
//Vars
//Movements Vars
public float runSpeed;
Rigidbody mybody;
Animator myAnimator;
bool playerDirectionE;
#endregion
// Use this for initialization
void Start () {
mybody = GetComponent<Rigidbody>();
myAnimator = GetComponent<Animator>();
playerDirectionE = true;
mybody.transform.eulerAngles = new Vector3(0, 90, 0);
}
// Update is called once per frame
void Update () {
}
void FixedUpdate()
{
float move = Input.GetAxis("Horizontal");
myAnimator.SetFloat("speed", Mathf.Abs(move)); //To intiate the charecter transition(move)
mybody.velocity = new Vector3(move * runSpeed, mybody.velocity.y, 0); //move charecter along the x axis, and keep y on gravity, not touching the z axis
if(move>0 && !playerDirectionE)
{
Flip();
}
else if(move<0 && playerDirectionE)
{
Flip();
}
}
void Flip()
{
playerDirectionE = !playerDirectionE;
Vector3 theScale = transform.localScale;
theScale.z *= -1;
transform.localScale = theScale;
}
}
I am using the following client information to send commands over the network:
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using System.Collections.Generic;
public class PlayerSyncRotation : NetworkBehaviour {
[SyncVar(hook ="OnPlayerRotSynced")]
private float syncPlayerRotation;
[SerializeField]
private Transform playerTransform;
private float lerpRate = 15;
private float lastPlayerRot;
private float threshold = 1;
private List<float> syncPlayerRotList = new List<float>();
private float closeEneough = 0.3f;
[SerializeField]
private bool userHistoricalInterpolation;
[Client]
void OnPlayerRotSynced(float latestPlayerRotation)
{
syncPlayerRotation = latestPlayerRotation;
syncPlayerRotList.Add(syncPlayerRotation);
}
[Command]
void CmdProvideRotationsToServer(float playerRot)
{
syncPlayerRotation = playerRot;
}
[Client]
void transmitRotations()
{
if (isLocalPlayer)
{
if(CheckIfBeyondThreshold(playerTransform.localScale.z, lastPlayerRot)){
lastPlayerRot = playerTransform.localScale.z;
CmdProvideRotationsToServer(lastPlayerRot);
}
}
}
bool CheckIfBeyondThreshold(float rot1, float rot2)
{
if (Mathf.Abs(rot1 - rot2) > threshold)
{
return true;
}
else
{
return false;
}
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
lerpRotation();
}
void FixedUpdate()
{
transmitRotations();
}
void lerpRotation()
{
if (!isLocalPlayer)
{
HistoricalInterpolation();
}
}
void HistoricalInterpolation(){
if (syncPlayerRotList.Count > 0)
{
LerpPlayerRotation(syncPlayerRotList[0]);
if(Mathf.Abs(playerTransform.localEulerAngles.z - syncPlayerRotList[0]) < closeEneough)
{
syncPlayerRotList.RemoveAt(0);
}
Debug.Log(syncPlayerRotList.Count.ToString() + "syncPlayerRotList Count");
}
}
void LerpPlayerRotation(float rotAngle)
{
Vector3 playerNewRot = new Vector3(0, 0, rotAngle);
playerTransform.rotation = Quaternion.Lerp(playerTransform.rotation, Quaternion.Euler(playerNewRot),lerpRate*Time.deltaTime);
}
}
My rotation looks fine on the client, but over the network on the second client, the rotation is broken and looks very wrong.
I have attached a link to a Webm where you can see the short video snippet of my problem HERE.
Would anyone here have any input as to what I could be doing wrong or how I could fix this issue? any suggestions would be appreciated.
Instead Using your custom code, i will like to say you that use Unet NetworkTransform. It is Unet high level API with different option of customization.
A component to synchronize the position and rotation of networked
objects(more).
Unet HLAPI are open source so you can also get the coding of the networkTransform at bitbucket.