I am trying to make a multiplayer air hockey game in Unity, but encountered some problems. When the first user creates the room, the hockey puck is spawned along with the first player's mallet (the object you hit the puck with). When the second player connects to the Photon server, their mallet is spawned.
The issue is when the second player hits the puck with his mallet, the Rigidbody physics don't work on the puck. The puck slides right along the mallet, but doesn't bounce off the mallet.
I am new to Unity, so I don't know what part of the code to post. But this is the code where I spawn the items:
private void Start() {
Vector2 puckPosition = new Vector2(0,0);
Vector2 randPos = new Vector2(Random.Range(minX, maxX), Random.Range(minY, maxY));
if(CreateAndJoinRooms.intHold == 0) { // If the user created the room, the result is 0
PhotonNetwork.Instantiate(puckPrefab.name, puckPosition, Quaternion.identity);
}
PhotonNetwork.Instantiate(playerPrefab.name, randPos, Quaternion.identity);
}
Mallet Prefab:
Puck Prefab:
You probably need to add a RigidBodyView component
It sounds like the problem is with Photons object ownership. According to the images, the puck prefabs Ownership Transfer = Fixed, which means it will never change. So it's is spawned and controlled by player 1 (as the Master Client), and player 1 is responsible for moving/controlling it.
In this case, Player 1 spawns the puck, player 2 strikes it and affects its Rigidbody2D, but then the next PhotonView Transform & Rigidbody2D updates are received, which set the location & velocity according to player 1s view, ignoring player 2s impact.
A some possible solutions:
Setup a Photon RPC or Photon Event that Player 2 calls to let the Master Client know an impact has happened and to adjust the physics.
Change the OwnerShip Transfer to Take Over, and when a collision is detected have the colliding player take ownership of the puck.
Related
I made a zombie with a Navmesh
I made the zombie follow the player by agent.destination
I made the zombie if close to target he will start attacking
-My question is how to stop the zombie from waking towards the player if he is in attack state but keep him rotating towards the player because if i set the navemesh agent speed to 0 he will stop rotating too.
I was trying to add a comment, but need more reputation for that. So had to make an "Answer" to reply.
Are you using the same speed var to multiply with the speed of your zombie to also multiply the rotation with?
If so, try adding a seperate var for the rotation speed.
enter image description hereI'm using mirror for local server between multiply gamePlayers.
I have a problem sync non players objects.
I want each Player to have a button to be able to rool two dices and that the player on host will be able to see what client do and apposite. I'm still confused , don't know when to use [Command] and [ClientRpc]
btw, I create my dices like that, and called this on the method OnStartServer():
GameObject newPrize = Instantiate(prizePrefab.gameObject, spawnPosition, Quaternion.identity);
// add this game object to all clients
NetworkServer.Spawn(newPrize);
Thank you so much!
I know the title isnt very explanatory, but here's my problem:
I have a player (merely a cube with a rigidbody, a collider and a movement script), and I have a floor made of small 1 by 1 by 1 cubes (cubes with box colliders).
For some reason unknown to me, when my player cube falls and tries to collide horizontally with the floor, he just phases through... But want him to get blocked by the cubes just like it does vertically. Any help would be greatly appreciated ;)
heres how the scene looks like
heres a cube object
heres the player object
Here's a gif of the player going through the floor
Here's my c# player movement script (I know its very bad, but I prefer to put this here just in case its linked to my problem) :
void ApplyMovement()
{
transform.position += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
}
If you need any more info to help me just tell me, I'll provide it as fast as I can.
The value of
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))
is framerate-dependent. This means the faster the framerate the faster your object will move. This is usually not what you want. Instead use Time.deltaTime
// Adjust the speed in the inspector
public float speedMultiplicator = 1;
//...
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * speedMultiplicator * Time.deltaTime
to get a framerate-independent movement. Also see the example in Input.GetAxis.
When dealing with RigidBody never change the transform.position (and rotation) directly!
If you would want to make the RigidBody jump to a certain position rather use
rigidBody.position = transform.position + ...;
However what you want is a smooth movement in order to keep the collision detection intact. So you should use RigidBody.MovePosition instead
rigidBody.MovePosition(transform.position + ...);
You don't have to deal with force etc.
Also add a RigidBody component to the floor objects. Even ifnthe object is not moving this improves the collision detection (at the cost of performance in the Physics engine ofcourse). And since the objects are not supposed to move set
isKinematic -> true
use Gravity -> false
you can also set freeze position and freeze rotation.
On both floor and player objects set Collision Detection -> Continous Dynamic. This improves the collision detection and looks for collisions also between frames.
Be aware, however, that dynamic detection is quite expensive so use it only if there is still trouble with too fast objects.
On the player you might want to also use interpolate as well.
Finally
Note that continuous collision detection is intended as a safety net to catch collisions in cases where objects would otherwise pass through each other, but will not deliver physically accurate collision results, so you might still consider decreasing the fixed Time step value in the TimeManager inspector
to make the simulation more precise, if you run into problems with fast moving objects.
For more information see the RigidBody manual and the Colliders manual
I recreated the scenario you described on my end. I put your "ApplyMovement" code in "Update". I was basically able to reproduce your results.
It seems to me that the issue might be Freezing Position X/Z on the Player. I think since you are doing that, you're telling the Rigidbody component that it is not allowed to modify the X/Z positions of the objects as part of it's collision resolution and physics simulation. When I turn those two off, I get results that are (I think) closer to what you're looking for.
One note: your "ApplyMovement" code is frame-locked, meaning your player will move at different speeds at different frame rates. To solve this, you'd need to multiply your Input.GetAxis values by Time.deltaTime.
Also, if your player moves too fast, it'll still be able to pass through collisions and cause odd behavior, so be sure to limit the max movement rate of the player to some reasonable value.
You should be applying a force to the Rigidbody of the character instead of directly manipulating the transform.position (this is preventing the physics engine from resolving the collisions). You're also freezing the X and Z position on the Rigidbody; you don't want that because it entirely prevents the Rigidbody from manipulating those values.
Instead of transform.postion += ... first get a reference to the Rigidbody somewhere in your script (best done in an Awake() method):
private Rigidbody _body;
private void Awake() {
_body = GetComponent<Rigidbody>();
}
Then make sure the vector built from your inputs is being applied to the object's "movement," not its position:
Vector3 inputVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
// You can multiply this vector by a float to adjust "speed"
_body.ApplyForce(inputVector, ForceMode.VelocityChange);
Finally, you should read up on the different ForceMode options and decide which one fits your preferences: https://docs.unity3d.com/ScriptReference/ForceMode.html
Don't forget this should happen in a FixedUpdate(), not an Update() (all physics operations should be done in FixedUpdate())
As a side note, there is also the possibility your rigidbodies still up moving too quickly and passing through each-other. Even when you're using forces and velocities, this is possible so if your run into this case down the line, investigate Collision Detection Modes. TLDR; they're settings for performance vs accuracy trade-offs.
I don't know how can I do it. You lose a game, if gameobject falls down and collides with the collider. I want to add a function that asks to the player if he wants another try, if yes it will reverse some time so the gameobject that fall down will be back on the screen and the user is allowed to play once again. Is there some sort of time function/method to do this?
Hope you understand.
void OnCollisionEnter2D(Collision2D col) {
if(col.gameObject.tag=="Collider") {
Vector2 checkpoint = new Vector2(transform.position.x, transform.position.y +5)
}
}
void Reset(){
this.transform.position = checkpoint;
}
I created a child object for that collider. And I moved the child to where I wanted the player to live when I collided with the collider.
Void OnCollisionEnter2D(Collision2D col)
{
if(col.gameobject.tag=="die")
{
checkpoint = col.transform.GetChil(0).position;
}
}
void Reset(){
Player.transform.position = checkpoint;
}
Your error is because you are missing the new keyword before Vector2
When using C# you need to use the new keyword in front of all
constructors. Constructors are like functions that are used to create
new objects (or scructs). They always have the same name as the type
of object you are creating.
So you should write
Vector2 checkpoint = new Vector2(transform.position.x, transform.position.y +5)
instead of:
Vector2 checkpoint = Vector2(transform.position.x, transform.position.y +5)
Edit: Now you edited your question without the error, and since you are still trying to find a method that moves back in time what happened in Unity, I can tell you that that thing doesn't exist. However you can implement it yourself. I would recommend you something like this:
If it is a platform 2D game, like Mario Bros style, you can place in
your scene a sequence of trigger that are activated when the player
go through them.
Then you can have a boolean array with a length n equal to the
number of triggers, and then a matrix nx2 ( number of triggers x
coordinates of each trigger [x,y] ).
Initially all the elements in the array has a false value, and
every time a trigger is activated the correcponding element in the
array changes to true.
When the player dies, it checks all elements in the array, until it
reaches the last true element (this would be the last triggered
activated).
With the index form the previous step you access the matrix of
triggers and you extract both elements (x and y coordinate). Then you
use that value in:
Using your script:
Vector2 checkpoint = new Vector2(xCoordinate, yCoordinate);
There is no in built function to reverse time in unity, this would require unity to record all events up until that point.
But given your example, what you could do is create a 'checkpoint' where the scene is set up in a certain way and objects are in specific positions. Like in Mario where you fall down, it plays some music to show you failed then it puts Mario back in a certain position. Just have a function that changes the player position to the checkpoint position. The same applies to any other gameobject you need to reset.
public void Reset()
{
player.position = checkpoint.position;
}
I am trying to spawn 2 Players (host and client) at 2 different locations.
I have no idea how to do this because the player are automatically spawned by the network manager.
I have tried the following but failed horribly :(.
[Command]
void CmdSpawn()
{
var go = (GameObject)Instantiate(
gameObject,
transform.position + new Vector3(0,1,0),
Quaternion.identity);
NetworkServer.SpawnWithClientAuthority(go, connectionToClient);
}
How Can I Spawn Player object at a specific location?
NetworkManager already supports spawn positions.
Just add GameObjects where you want players to spawn and give them the NetworkStartPosition component. NetworkManager will automatically detect the start positions and automatically use them according to your setting of "Player Spawn Method" either "Random" (one spawn position is randomly chosen for every player) or "Round Robin" (player #0 spawns at first position, player #1 at second and so forth).
Is there any problems with changing position in a script for player object? For example you could try adding following script on your player object:
void Start () {
if (isServer) // host runs
{
transform.position = new Vector3(0,0,0);
}
else if (isClient) // client runs
{
transform.position = new Vector3(10,0,10);
}
}
i was facing a similar problem, here is the solution in this thread, read til the end.
http://forum.unity3d.com/threads/which-function-to-override.391076/
Make a GameObject and attach a NetworkStartPosition to it. Then, place it somewhere. If you want more than 1 spawn point, you can CTRL+D that object. Then, go to NetworkManager and select Round Robin for spawning first to first, second to second etc. select Random for random spawn points.