I was following this tutorial on the Unity docs, but wanted to change my version to fire towards the mouse position. The host works fine but when running the client the bullets fire towards the mouse position relative to the host client (usually just off to the side).
Here is my code as is:
public class PlayerMove : NetworkBehaviour {
public GameObject bulletPrefab;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (!isLocalPlayer)
return;
var x = Input.GetAxis("Horizontal") * 0.1f;
var z = Input.GetAxis("Vertical") * 0.1f;
transform.Translate(x, 0, z);
if (Input.GetMouseButtonDown(0))
{
CmdFire();
}
}
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.red;
}
[Command]
void CmdFire()
{
// create the bullet object from the bullet prefab
// make the bullet move away in front of the player
Vector2 target = Camera.main.ScreenToWorldPoint(new Vector2(Input.mousePosition.x, Input.mousePosition.y));
Vector2 myPos = new Vector2(transform.position.x, transform.position.y + 1);
Vector2 direction = target - myPos;
GameObject projectile = (GameObject)Instantiate(bulletPrefab, myPos, transform.rotation);
projectile.GetComponent<Rigidbody2D>().velocity = direction * 4f;
// spawn the bullet on the clients
NetworkServer.Spawn(projectile);
// make bullet disappear after 2 seconds
Destroy(projectile, 2.0f);
}
}
I have also tried to move the "velocity = direction" to a new bullet script but it always performs the same.
How can I use a 'local' mouse position, if that's the solution here?
You need to synchronize the direction, rotation and position from your client on all the other clients if you want them to see what client sees.
Also - [Command] only runs on the server, you probably want to spawn the bullet on all the clients connected to the server so you should run [ClientRpc] from your [Command]
public class PlayerMove : NetworkBehaviour {
public GameObject bulletPrefab;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (!isLocalPlayer)
return;
var x = Input.GetAxis("Horizontal") * 0.1f;
var z = Input.GetAxis("Vertical") * 0.1f;
transform.Translate(x, 0, z);
if (Input.GetMouseButtonDown(0))
{
Fire();
}
}
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.red;
}
void Fire()
{
Vector2 _target = Camera.main.ScreenToWorldPoint(new Vector2(Input.mousePosition.x, Input.mousePosition.y));
Vector2 _myPos = new Vector2(transform.position.x, transform.position.y + 1);
Vector2 _direction = _target - _myPos;
Vector3 _rot = transform.rotation.eulerAngles;
CmdFire(_myPos, _myDir, _rot);
}
[Command]
void CmdFire(Vector2 _myPos, Vector2 _myDir, Vector3 _rot)
{
RpcFire(_myPos, _myDir, _rot);
}
[ClientRpc]
void RpcFire(Vector2 _myPos, Vector2 _myDir, Vector3 _rot)
{
// create the bullet object from the bullet prefab
// make the bullet move away in front of the player
GameObject _projectile = (GameObject)Instantiate(bulletPrefab, _myPos, Quaternion.Euler(_rot);
_projectile.GetComponent<Rigidbody2D>().velocity = direction * 4f;
// spawn the bullet on the clients
NetworkServer.Spawn(_projectile);
// make bullet disappear after 2 seconds
Destroy(_projectile, 2.0f);
}
}
Related
I have a problem with my humanoid character's Foot IK.
I'm building an Isometric Top-Down game with NavMesh to move the Player on click, and I wanted to add some life to the characters so I decided to add IK Foot Placement by following this tutorial.
It worked well, but I wanted to go further by making it more sensitive to colliders so the player's foot gets placed on the ground's surface perfectly.
This script below works well when the ground is rotated.
I tried to fix it a lot but it still doesn't work.
[ Preview Images ]
Here's my script:
using UnityEngine;
using UnityEngine.AI;
public class IKFootPlacement : MonoBehaviour
{
public bool ikActive = false;
public Animator anim;
public NavMeshSurface navmesh;
public LayerMask layerMask;
public Transform LeftFoot_Transform;
public Transform RightFoot_Transform;
public float LeftFoot_DistanceToGround;
public float RightFoot_DistanceToGround;
public float footGap = 0.0f;
private Vector3 L_TargetPosition;
private Vector3 R_TargetPosition;
private Ray L_Ray;
private Ray R_Ray;
void Start()
{
anim = GetComponent<Animator>();
}
void OnAnimatorIK(int layerIndex)
{
if (anim)
{
// Vector3 LeftFoot_position = anim.GetIKPosition(AvatarIKGoal.LeftFoot);
// Vector3 RightFoot_Position = anim.GetIKPosition(AvatarIKGoal.RightFoot);
float IKLeftWeight = anim.GetFloat("IKLeftFootWeight");
anim.SetIKPositionWeight(AvatarIKGoal.LeftFoot, IKLeftWeight);
anim.SetIKRotationWeight(AvatarIKGoal.LeftFoot, IKLeftWeight);
float IKRightWeight = anim.GetFloat("IKRightFootWeight");
anim.SetIKPositionWeight(AvatarIKGoal.RightFoot, IKRightWeight);
anim.SetIKRotationWeight(AvatarIKGoal.RightFoot, IKRightWeight);
//~ Left Foot
if (LeftFoot_Transform)
{
RaycastHit L_Hit;
L_Ray = new Ray(LeftFoot_Transform.position + Vector3.up, Vector3.down);
if (Physics.Raycast(L_Ray, out L_Hit, 2f, layerMask))
{
L_TargetPosition = L_Hit.point;
LeftFoot_DistanceToGround = Vector3.Distance(LeftFoot_Transform.position, L_TargetPosition);
if (LeftFoot_DistanceToGround > 0.15)
L_TargetPosition.y -= LeftFoot_DistanceToGround;
else
L_TargetPosition.y += LeftFoot_DistanceToGround;
L_TargetPosition.y += footGap;
anim.SetIKPosition(AvatarIKGoal.LeftFoot, L_TargetPosition);
anim.SetIKRotation(AvatarIKGoal.LeftFoot, Quaternion.LookRotation(transform.forward, L_Hit.normal));
}
}
//~ Right Foot
if (RightFoot_Transform)
{
RaycastHit R_Hit;
R_Ray = new Ray(RightFoot_Transform.position + Vector3.up, Vector3.down);
if (Physics.Raycast(R_Ray, out R_Hit, 2f, layerMask))
{
R_TargetPosition = R_Hit.point;
RightFoot_DistanceToGround = Vector3.Distance(RightFoot_Transform.position, R_TargetPosition);
if (RightFoot_DistanceToGround > 0.15)
R_TargetPosition.y -= RightFoot_DistanceToGround;
else
R_TargetPosition.y += RightFoot_DistanceToGround;
R_TargetPosition.y += footGap;
anim.SetIKPosition(AvatarIKGoal.RightFoot, R_TargetPosition);
anim.SetIKRotation(AvatarIKGoal.RightFoot, Quaternion.LookRotation(transform.forward, R_Hit.normal));
}
}
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.magenta;
Gizmos.DrawWireSphere(L_TargetPosition, 0.05f);
Gizmos.DrawWireSphere(R_TargetPosition, 0.05f);
Gizmos.color = Color.red;
Gizmos.DrawRay(L_Ray);
Gizmos.DrawRay(R_Ray);
}
}
I am trying to create a gun script however after the bullet prefab instantiates, it doesn't travel in the correct direction(Straight). The function used to create bullets in Shoot() which is called when the Update loop gets the input from GetMouseButton(0).
public class CharController : MonoBehaviour {
[SerializeField]
float moveSpeed = 4f;
public float aimSpeed;
Vector3 mousePos;
Vector3 forward, right;
public GameObject bulletSpawnPoint;
public GameObject bullet;
public float bullet_Speed;
public float fireRate;
void Start () {
forward = Camera.main.transform.forward;
forward.y = 0;
forward = Vector3.Normalize(forward);
right = Quaternion.Euler(new Vector3(0, 90, 0)) * forward;
}
void Update () {
if (Input.GetMouseButton(0))
{
transform.position += (-transform.position + mousePos).normalized * aimSpeed * Time.deltaTime;
transform.position = new Vector3(transform.position.x, 2.5f, transform.position.z);
Shoot();
}
}
void Shoot()
{
GameObject temp_Bullet_Handler;
temp_Bullet_Handler = Instantiate(bullet, bulletSpawnPoint.transform.position, bulletSpawnPoint.transform.rotation) as GameObject;
//temp_Bullet_Handler.transform.Rotate(Vector3.left * 90);
Rigidbody temp_Rigidbody;
temp_Rigidbody = temp_Bullet_Handler.GetComponent<Rigidbody>();
temp_Rigidbody.AddForce(Vector3.forward * Time.deltaTime * 10f);
Destroy(temp_Bullet_Handler, 10.0f);
}
}
If anyone has any information on what causes the bullets not to travel in a straight direction from the instantiation point, I would love to have your input.
Thanks in advance
Your Update moves the bullet in a direction which is based on it's position. Change that into a direction vector, like your "forward" instead of transform.position.
I was trying to achieve this kind of player ball movement:
Catch Up (Ketchapp)
From my side I have tried and record a video of my current implementation:
CatchUpBallMovementDemo
Two kinds of problem, I was facing:
ball making so much jerk while moving on the plain track that I hope you have clearly noticed in my recorded video
when ball reach left or right edge and you try to swipe its making jerk again rather than remain restricted because clamping related code already added
I have just created a demo project so here I am providing the link for it so personally you can check and provide me a suggestion for making ball movement perfect.
Demo Project Source Link: CatchUpBallDemo
Demo Project SIZE 20MB
What at present making jerk in ball movement that I can't able to decide, whether its following camera jerk, whether ball not moving properly though I have created a plain track for checking purpose.
Ball Inspector Detail:
Complete code added within the working demo project. Share your suggestions with me to solve this.
Code Scripts:
BallController
[RequireComponent (typeof(Rigidbody))]
public class BallController : MonoBehaviour
{
//
private Rigidbody myRigidBody;
private bool isJumper;
private bool allowSpeedIncrease;
private BallInputHandler ballInputHandler;
private float speed;
private float speedMilestone;
private float jumpCounter;
private float scoreElapsedTime;
[SerializeField]
private bool isGrounded;
//
public float ballHorzRange;
public float ballStartSpeed;
public float ballTopSpeed;
public float smoothnessValue;
public float smoothnessX;
private void Awake ()
{
DoOnAwake ();
}
private void DoOnAwake ()
{
ballInputHandler = GetComponent<BallInputHandler> ();
myRigidBody = GetComponent<Rigidbody> ();
speed = ballStartSpeed;
speedMilestone = ballStartSpeed;
}
public void Start ()
{
DoOnStart ();
}
private void DoOnStart ()
{
// assinging player transform to camera to follow
Camera.main.GetComponent<CameraFollow> ().FollowPlayer (transform);
}
void Update ()
{
// slowly increase ball moving speed
if (allowSpeedIncrease) {
speed += Time.deltaTime;
if (speed >= speedMilestone) {
allowSpeedIncrease = false;
speed = speedMilestone;
}
}
}
void FixedUpdate ()
{
// do jumping
if (isJumper) {
jumpCounter++;
if (jumpCounter >= 3) {
isJumper = false;
jumpCounter = 0;
}
myRigidBody.AddForce (Vector3.up * 700f);
}
// applying continuous forward velocity
Vector3 nextVelocity = myRigidBody.velocity;
nextVelocity.x = ballInputHandler.horizontalInput * smoothnessX;
nextVelocity.z = speed;
if (isGrounded) {
nextVelocity.y = 0;
} else if (!isJumper) {
nextVelocity.y -= speed * 0.1f;
}
myRigidBody.velocity = nextVelocity.normalized * speed;
ClampingBallMovement ();
}
// ball horizontal movement limitation
private void ClampingBallMovement ()
{
Vector3 currRigidbodyPos = myRigidBody.position;
if (currRigidbodyPos.x <= -ballHorzRange || currRigidbodyPos.x >= ballHorzRange) {
currRigidbodyPos.x = Mathf.Clamp (currRigidbodyPos.x, -ballHorzRange, ballHorzRange);
myRigidBody.position = currRigidbodyPos;
}
}
void OnTriggerEnter (Collider other)
{
if (other.CompareTag (GameConstants.TAG_TRACK_SPAWNER)) {
GameController.Instance.SpawnPlateform ();
} else if (other.CompareTag (GameConstants.TAG_TRACK_DESTROYER)) {
Destroy (other.transform.parent.gameObject);
}
}
}
BallMeshRolling
public class BallMeshRolling : MonoBehaviour
{
private Vector3 ballLastPosition;
void Start ()
{
ballLastPosition = transform.parent.position;
}
void Update ()
{
// implementation-1
float speed = Vector3.Distance (transform.parent.position, ballLastPosition) * 30f;
transform.RotateAround (transform.position, Vector3.right, speed);
// float dragDifference = (transform.position.x - ballLastPosition.x) * 30f;
// transform.RotateAround (transform.position, Vector3.forward, dragDifference);
ballLastPosition = transform.parent.position;
}
}
CameraFollow
public class CameraFollow : MonoBehaviour
{
//
private Vector3 newPos;
private Vector3 initialPosition;
//
public Transform player;
public Vector3 offSet;
void Awake ()
{
initialPosition = transform.position;
}
void LateUpdate ()
{
if (!player)
return;
newPos = player.position + offSet;
newPos.x = ReMap (newPos.x);
newPos.y = Mathf.Clamp (newPos.y, initialPosition.y, initialPosition.y + 1f);
// transform.position = newPos;
transform.position = Vector3.Lerp (transform.position, newPos, 10f * Time.deltaTime);
}
public void FollowPlayer (Transform target)
{
player = target;
ResetCamera ();
}
public float ReMap (float value, float from1 = -4f, float to1 = 4f, float from2 = -2.5f, float to2 = 2.5f)
{
return (value - from1) / (to1 - from1) * (to2 - from2) + from2;
}
public void ResetCamera ()
{
transform.position = initialPosition;
}
}
I could solve the second problem by simply adding this to BallController.ClampingBallMovement():
private void ClampingBallMovement ()
{
Vector3 currRigidbodyPos = myRigidBody.position;
if (currRigidbodyPos.x <= -ballHorzRange || currRigidbodyPos.x >= ballHorzRange) {
currRigidbodyPos.x = Mathf.Clamp (currRigidbodyPos.x, -ballHorzRange, ballHorzRange);
myRigidBody.position = currRigidbodyPos;
}
// I ADDED THIS
// Clamp the velocity as well
if (currRigidbodyPos.x <= -ballHorzRange && myRigidBody.velocity.x < 0 || currRigidbodyPos.x >= ballHorzRange && myRigidBody.velocity.x > 0)
{
myRigidBody.velocity = new Vector3(0, myRigidBody.velocity.y, myRigidBody.velocity.z);
}
}
you clamped the position but did not clamp the velocity as well.
I could not reproduce the first jerking arround on my PC.
I have a test 2D game where my player moved from left to right and when he reached the end of the screen it would just transform on the other side. I had a change of heart and made my player move diagonally. It did work, but I have no idea how to make the player stop when it hits the end of the screen. I don't want it to transform on the other side, but rather just stop. So far all my results are either some glitching on the edges or not stopping at all. I have provided my PlayerController script. Right now my player moves diagonally and he will just continue after the edge of the screen. If anyone can assist me I would be very grateful. I never thought I will deal with diagonal movement, but I really want to learn how to do it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
public float speed = 7;
public float speedy = 7;
public event System.Action OnPlayerDeath;
float screenHalfWidthInWorldUnits;
Rigidbody2D rb;
void Start () {
rb = GetComponent<Rigidbody2D>();
float halfPlayerWidth = transform.localScale.x / 2f;
screenHalfWidthInWorldUnits = Camera.main.aspect * Camera.main.orthographicSize;
}
void Update()
{
float inputX = Input.GetAxisRaw("Horizontal");
float velocity = inputX * speed;
transform.Translate(Vector2.right * velocity * Time.deltaTime);
}
public void MoveRight()
{
rb.velocity = new Vector2(speed, speedy);
}
public void MoveLeft()
{
rb.velocity = new Vector2(-speed, -speedy);
}
public void Stop()
{
rb.velocity = Vector2.zero;
}
void OnTriggerEnter2D(Collider2D triggerCollider)
{
if (triggerCollider.tag =="Box")
{
if (OnPlayerDeath != null)
{
OnPlayerDeath();
}
Destroy(gameObject);
}
}
}
You can check if the player is at what you define as the border of the map.
If you check this for the x and y axis respectively, you can then lock his x or y axis to the border and not further.
Here is an example of a script I made earlier that does that.
If I understand you correctly you would like to be able to move diagonally. In my sample script below you can move both straight and diagonally, you can also warp between the edges or stop at the edges as you spoke of wanting to.
This script is a bit more advanced than what you need probably, so let me know if something about it confuses you.
Please note that if you set the boolean _ShouldWarp to false he will stop at the border, otherwise he will warp from edge to edge of the map.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public float _Speed = 5f;
public WorldBounds _WorldBounds;
public bool _ShouldWarp; //If _ShouldWarp is false, will block players movement instead.
void Update()
{
Move();
WarpIfAtBoundary();
}
void Move()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
transform.Translate(Vector3.right * Time.deltaTime * _Speed * horizontal);
transform.Translate(Vector3.up * Time.deltaTime * _Speed * vertical);
}
void WarpIfAtBoundary()
{
//X Axis
//If player is at positive X boundary
if (transform.position.x > (_WorldBounds.xPlus + _WorldBounds.xBuffer))
{
if (_ShouldWarp) //Teleport/warp player is set to enabled
{
transform.position = new Vector3(_WorldBounds.xMinus, transform.position.y, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(_WorldBounds.xPlus + _WorldBounds.xBuffer, transform.position.y, transform.position.z);
}
}
//Else if player is at negative X boundary
else if (transform.position.x < (_WorldBounds.xMinus - _WorldBounds.xBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(_WorldBounds.xPlus, transform.position.y, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(_WorldBounds.xMinus - _WorldBounds.xBuffer, transform.position.y, transform.position.z);
}
}
//Y Axis
//If player is at positive Y boundary
if (transform.position.y > (_WorldBounds.yPlus + _WorldBounds.yBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yMinus, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yPlus + _WorldBounds.yBuffer, transform.position.z);
}
}
//Else if player is at negative Y boundary
else if (transform.position.y < (_WorldBounds.yMinus - _WorldBounds.yBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yPlus, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yMinus - _WorldBounds.yBuffer, transform.position.z);
}
}
}
}
//Set as serializable so it displays correctly in Unity's inspector window.
[System.Serializable]
public class WorldBounds
{
[Header("Bounds")]
public float xMinus = -9.4f;
public float xPlus = 9.4f;
public float yMinus = -9.4f;
public float yPlus = 9.4f;
[Header("BufferZone")]
public float xBuffer = 1f;
public float yBuffer = 1f;
}
EDIT:
With your additions will I be able to assign the movement to my two buttons. One is up and right and the other is down and left.
void Move()
{
float horizontal = Input.GetAxisRaw("Horizontal");
transform.Translate(Vector3.right * Time.deltaTime * _Speed * horizontal);
transform.Translate(Vector3.up * Time.deltaTime * _Speed * horizontal);
}
This should work to move diagonally left and down as well as up and right.
The change i made is to use the Horizontal input for both X and Y movement.
I don't need the warp. Just to step at the defined borders
You can set the Warp boolean to false or remove the warp parts from the code then :-), should work.
I see that the bullets are being fired at random positions and not actually in forward direction of the camera. What's wrong here and how should I fix it?
So I am using pooling and each time the bullet is enabled this code is run:
private void OnEnable()
{
transform.position = Camera.main.transform.position;
transform.rotation =Quaternion.identity;
GetComponent<Rigidbody>().AddForce((Camera.main.transform.forward + new Vector3(0, 0, 0)) * 5000);
Invoke("Destroy", 1.5f);
}
I have also changed it to the below code but even the second one doesn't work.
private void OnEnable()
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.position = Camera.main.transform.position;
rb.rotation = Quaternion.identity;
rb.AddForce((Camera.main.transform.forward + new Vector3(0, 0, 0)) * 5000);
Invoke("Destroy", 1.5f);
}
First of all make sure the code works with out pooling. Secondly disable the collider component on the bullet (they might be colliding with themselves).
I've quickly tried this on my machine and this is the result I get.
using UnityEngine;
public class BulletController : MonoBehaviour
{
[SerializeField]
GameObject bulletPrefab;
void Update()
{
GameObject bullet = Object.Instantiate(bulletPrefab);
Rigidbody body = bullet.GetComponent<Rigidbody>();
body.position = Camera.main.transform.position;
body.AddForce(Camera.main.transform.forward * 75f, ForceMode.Impulse);
}
}
Here is the code I use with direction, position and velocity variables.
void Inception::shootGeode(std::string typeGeode, const btVector3& direction) {
logStderr(VERBOSE, "MESSAGE: Shooting geode(s)...\n");
std::shared_ptr<Geode> geode;
glm::vec3 cameraPosition = m_camera->getPosition();
btVector3 position = glm2bullet(cameraPosition + 3.0f * glm::normalize(m_camera->getTarget() - cameraPosition));
if (typeGeode == "cube")
geode = m_objectFactory->createCube("cube", new btBoxShape(btVector3(1.0f, 1.0f, 1.0f)), position, "dice");
if (typeGeode == "sphere")
geode = m_objectFactory->createSphere("sphere", new btBoxShape(btVector3(1.0f, 1.0f, 1.0f)), position);
btVector3 velocity = direction;
velocity.normalize();
velocity *= 25.0f;
geode->getRigidBody()->setLinearVelocity(velocity);
}