So i'm currently working on a game with unity, it's an air hockey. And i would like to add a multiplayer mode (1 vs 1).
So after the player have a match with an opponent, they are connected in a room where the game begins.
But i'm having issue when i want to receive the opponent message.
In the player script movement, i add this on the void update()
Multiplayer.Instance.SendMyUpdate(positionX, PositionZ);
and in the multiplayer script, i add this:
public void SendMyUpdate(float posX, float posZ) {
string PlayerUserNameString = PlayGamesPlatform.Instance.RealTime.GetSelf ().DisplayName;
char[] characters = PlayerUserNameString.ToCharArray ();
string data = characters + ":" + posX + ":" + posZ;
byte[] bytedata = System.Text.ASCIIEncoding.Default.GetBytes (data);
PlayGamesPlatform.Instance.RealTime.SendMessageToAll (false, bytedata);
}
And on the method OnRealTimeMessageReceived:
string rawdata = System.Text.ASCIIEncoding.Default.GetString (data);
string[] cut = rawdata.Split (new string[] { ":" }, System.StringSplitOptions.RemoveEmptyEntries);
OpponentUserName = System.Convert.ToSingle (cut[1]).ToString();
Transform target = GameObject.Find ("mallet Opponent").transform;
Vector3 newpos = new Vector3
(
System.Convert.ToSingle(cut[2]),
0,
System.Convert.ToSingle(cut[3])
);
After i wrote this and build it on two devices, when the room is connected and the game begins, the opponent player doesn't move at all, and i don't know where the issue.
Any ideas?
Arrays are zero based so opponent user name should be cut[0] and:
System.Convert.ToSingle(cut[3])
cut[3] will look for the 4th split result and there are only three so an exception will occur. That is enough to prevent the method working and the position updating. If so there should also be an error in the console log.
However perhaps the OnRealTimeMessageReceived is not even being called. You need to throw in some breakpoints and debug, or add some debug logs to see how far things are getting. If it isn't even getting to a method you expect then the question can be rephrased "why is method X not being called"
Related
I have the following lines of code. I am trying to set "MouseLook.hit" to either the gameObject.name or to "no" if the raycast does not hit. The if statement works, such that the MouseLook.hit prints in Unity. However, I can never receive the object on the other side (it is received in MATLAB). BUT, the "no" in the else statement is received in MATLAB. ALSO, I sometimes receive the message for some of the objects that I have in my Unity environment, but not for the specific ones I want (I have tried swithching to either mesh or box colider). Can you see something wrong with the code? Thank you!
ray = new Ray(transform.position, transform.forward);
if (Physics.Raycast(ray, out raycastHit))
{
MouseLook.hit = raycastHit.collider.gameObject.name;
print(MouseLook.hit);
}
else
{
MouseLook.hit = "no";
}
Byte[] sendBytes5 = Encoding.UTF8.GetBytes(MouseLook.hit);
mySocket1.GetStream().Write(sendBytes5, 0, sendBytes5.Length);
Byte[] sendBytes6 = Encoding.UTF8.GetBytes(" ");
mySocket1.GetStream().Write(sendBytes6, 0, sendBytes6.Length);
I tried to change the encoding, I tried to change the objects in the hierarchy, I tried to change the if and else if statement, I tried to change to meshcolider to boc colider for the objects I am aiming at in the game.
I have a simple game published in Google Play. When player wins the game his score should be incremented in leaderboard. My problem is that when player wins the game, app stops. I think that problem is in PlayGamesPlatform.Instance.LoadScores because when I removed this part, no one had a problem. Also, I want to notice that not every player has such problem in game. This problem happens just to those, who haven't ever won the game (they have no score in leaderboard). So, PlayGamesPlatform.Instance.LoadScores works only to those who already have some score in leaderboard.
My script:
PlayGamesPlatform.Instance.LoadScores(GPGSIds.leaderboard_rating, GooglePlayGames.BasicApi.LeaderboardStart.PlayerCentered, 1, GooglePlayGames.BasicApi.LeaderboardCollection.Public, GooglePlayGames.BasicApi.LeaderboardTimeSpan.AllTime, (GooglePlayGames.BasicApi.LeaderboardScoreData data) =>
{
long score;
if (long.TryParse(data.PlayerScore.formattedValue, out score))
Social.ReportScore(score + 50, GPGSIds.leaderboard_rating, (bool success) => { });
else
Social.ReportScore(50, GPGSIds.leaderboard_rating, (bool success) => { });
});
Try this google sample from github
Using PlayGamesPlatform.LoadScores()
This method uses the PlayGamesPlatform directly. This approach provides additional flexibility and information when accessing the leaderboard data.
PlayGamesPlatform.Instance.LoadScores(
GPGSIds.leaderboard_leaders_in_smoketesting,
LeaderboardStart.PlayerCentered,
100,
LeaderboardCollection.Public,
LeaderboardTimeSpan.AllTime,
(data) =>
{
mStatus = "Leaderboard data valid: " + data.Valid;
mStatus += "\n approx:" +data.ApproximateCount + " have " + data.Scores.Length;
});
The parameters for LoadScores() are:
leaderboardId start position (top scores or player centered) row count
leaderboard collection (social or public) time span (daily, weekly,
all-time) callback accepting a LeaderboardScoreData object. The
LeaderboardScoreData class is used to return information back to the
caller when loading scores. The members are:
1. Id - the leaderboard id 2. Valid - true if the returned data is valid (the call was successful) 3. Status - the ResponseStatus of the
call 4. ApproximateCount - the approximate number of scores in the
leaderboard 5. Title - the title of the leaderboard 6. PlayerScore -
the score of the current player 7. Scores - the list of scores 8.
PrevPageToken - a token that can be used to call LoadMoreScores() to
get the previous page of scores. 9. NextPageToken - a token that can
be used to call LoadMoreScores() to get the next page of scores.
void GetNextPage(LeaderboardScoreData data)
{
PlayGamesPlatform.Instance.LoadMoreScores(data.NextPageToken, 10,
(results) =>
{
mStatus = "Leaderboard data valid: " + data.Valid;
mStatus += "\n approx:" +data.ApproximateCount + " have " + data.Scores.Length;
});
}
Additional reference How to get the user score value from Google Play Services Leaderboard.
P.S.:
Try setting the scores of all players to default 0 so players who havent played yet can make calls to loadScores.
I would like to generate a 3D scenario for a traffic simulation.
The main idea would be having SUMO running a simulation and then getting the direction, speed and coordinates (X,Y) from each vehicle, so that I would create 3D models for this cars.
For this purpose, I was thinking about using some kind of TCP/IP communication between Unity and SUMO. Since this is possible while communicating SUMO with a network simulator such as OMNeT++, I was wondering if this would also be possible. I don't need to control the simulation in SUMO from Unity, just retrieve data regarding the vehicles in the network.
Unfortunately, I have no remarkable experience with Unity, so I cannot provide any code trying to achieve this...
EDIT:
As requested, I included some code. However, I only have code in Java.
String configFile = "test/resources/sumo_maps/Test2/Test2.sumo.cfg";
SumoTraciConnection trial = new SumoTraciConnection(configFile,-1);
trial.runServer();
Collection<Vehicle> vehicles = trial.getVehicleRepository().getAll().values();
for(Vehicle car : vehicles){
bw.write(time + " // The vehicle with ID: " + car.getID()+ " is driving "
+ "with a speed of "+ car.getSpeed() + " and is in coordinates x: " +car.getPosition().getX()+
" and y: " + car.getPosition().getY());
bw.newLine();
}
Now, let's proceed to get a bit into the class SumoTraciConnection and its methods. This class is part of the mentioned (in the comments) library Traci4j.
It can be found in GitHub in case you need more info: https://github.com/egueli/TraCI4J/blob/master/src/java/it/polito/appeal/traci/SumoTraciConnection.java
The constructor:
public SumoTraciConnection(String configFile, int randomSeed) {
this.randomSeed = randomSeed;
this.configFile = configFile;
}
Now the runServer() method (I put the one with a boolean argument because if no parameter is given then it is automatically called with a false) Basically, this boolean is used to determine wheter the GUI version of SUMO or the console version will be ran:
public void runServer(boolean withGui) throws IOException, InterruptedException {
retrieveFromURLs(); //Checks if the configFile given has an "http://" at the beggining, in order to download the file
int port = findAvailablePort(); //creates a Socket and finds a port with ServerSocket.getLocalPort()
runSUMO(port, withGui); //It is used to run SUMO with different options, such as the configFile for the simulation, the remote port... sumoProcess is set here as: sumoProcess = Runtime.getRuntime().exec(argsArray);, where argsArray contains the different options mentioned
tryConnect(InetAddress.getLocalHost(), port, sumoProcess); // tryConnect basicaly calls this method tryConnectOnce, which connects as a client to the sumo process mentioned before, and does some checks that everything is correct.
postConnect(); //I will explain this function after
}
postConnect() initialices the DataInput and DataOutput streams and creates the repositories. I show now the relevant parts of the code:
dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
vehicles = new HashMap<String, Vehicle>();
edgeRepo = new Repository.Edges(dis, dos, newIDListQuery(Constants.CMD_GET_EDGE_VARIABLE));
addStepAdvanceListener(edgeRepo);
laneRepo = new Repository.Lanes(dis, dos, edgeRepo, newIDListQuery(Constants.CMD_GET_LANE_VARIABLE));
vehicleListQuery = newIDListQuery(Constants.CMD_GET_VEHICLE_VARIABLE);
addStepAdvanceListener(new StepAdvanceListener() {
public void nextStep(double step) {
vehicleListQuery.setObsolete();
}
});
vehicleListBefore = new HashSet<String>(vehicleListQuery.get());
vehicleRepo = new Repository.Vehicles(dis, dos, edgeRepo, laneRepo, vehicles, vehicleListQuery);
addStepAdvanceListener(vehicleRepo);
Where one StepAdvanceListener is just the following(I cannot explain exactly what is this for but I understand that is something that allow us to realize the new simulationstep has been done, so we have to update the repositories):
//Interface for an object that can be notified when the simulation advances by one step.
public interface StepAdvanceListener {
/**
* Callback for step advancement.
* #param step the new simulation time, in seconds
*/
void nextStep(double step);
}
Up to here, it would be the part related to the connection with SUMO. In the next edit (I need some rest right now..) I'll put the parts related with the Repositories and the Data retrieval
Thanks in advance!
I have an object and a script attached to it.
I want to send data to a web server in script's Update function.
So I create a WWW object.
But after some time Unity begins to report "thread shouldn't be running anymore".
Here is the Update function:
void Update ()
{
//ambil tindakan dari server
//bikin object www
//bikin request ke localhost/vacuum?r=index/action
//ambil hasilnya (json)
//ambil perintah
//eksekusi perintah
//scan lingkungan
var fwd = transform.TransformDirection (Vector3.forward);
var left = transform.TransformDirection (Vector3.left);
var right = transform.TransformDirection (Vector3.right);
var back = transform.TransformDirection (Vector3.back);
RaycastHit hit_fwd = new RaycastHit(),
hit_left = new RaycastHit(),
hit_right = new RaycastHit(),
hit_back = new RaycastHit();
bool bool_hit_fwd, bool_hit_left, bool_hit_right, bool_hit_back;
float
distance_fwd = 0.0f,
distance_left = 0.0f,
distance_right = 0.0f,
distance_back = 0.0f;
bool_hit_fwd = Physics.Raycast (transform.position, fwd, out hit_fwd, 50);
bool_hit_left = Physics.Raycast (transform.position, left, out hit_left, 50);
bool_hit_right = Physics.Raycast (transform.position, right, out hit_right, 50);
bool_hit_back = Physics.Raycast (transform.position, back, out hit_back, 50);
if (bool_hit_fwd)
{
distance_fwd = hit_fwd.distance;
}
if (bool_hit_left)
{
distance_left = hit_left.distance;
}
if (bool_hit_right)
{
distance_right = hit_right.distance;
}
if (bool_hit_back)
{
distance_back = hit_back.distance;
}
transform.Rotate(0, 0.01f, 0);
print(
"rot-y/pos-x/pos-y :: fwd/left/right/back = " +
transform.rotation.eulerAngles.y + '/' +
transform.position.x + '/' +
transform.position.y + '/' +
" :: " +
distance_fwd + '/' +
distance_left + '/' +
distance_right + '/' +
distance_back);
String url = "http://localhost:1234/minibrain?" +
"roty=" + transform.rotation.eulerAngles.y.ToString() +
"&posx=" + transform.position.x.ToString() +
"&posy=" + transform.position.y.ToString() +
"&fwddist=" + distance_fwd.ToString() +
"&leftdist=" + distance_left.ToString() +
"&rightdist=" + distance_right.ToString() +
"&backdist=" + distance_back.ToString();
WWW www = new WWW(url);
}
There is no error. Data was received correctly by the web server. But the data transmission rate decreased greatly. Like down to 10 transmissions per second from 100 transmissions per second.
Is there a way to create WWW object without causing "thread shouldn't be running anymore"?
The problem here is most likely that you run everything in your Update(). That will generally steam ahead as fast as it can. Your call to WWW will return immediately (it won't wait until all actions are done) and you move on to your next frame.
As a result, if your Update runs fast enough, you'll end up with more and more WWW objects that haven't completed. I don't know how fast it is currently running, but you have to ask yourself if you either need that many data points, or if going trough a WWW call is the best approach. If available on your setup, a socket connection might work better.
If you're happy with sending data as fast as it can be handled, make sure you check for the isDone by making the call a coroutine, or in that case just yield for its return. (Don't use a while loop on it) Or perhaps just determine a regular interval at which you'd like the data, and send it at that, if that ends up being easier on your setup there.
Use coroutines. It is bad experience to implement web requests in Update() function, because web requests need some time to be executed.
I'm having a problem with a youtube cache I'm trying to make (my internet connection is really slow). It works by detecting if a videoplayback page is requested and saves the response to the disk. It works fine with lightspark and the html5 player on FireFox, but when I try it on Google Chrome I get a Write Failure in RespCacheCallback.
I have the source here as it is too long to be posted with the question.
I forgot to add the range to the ID created in the program when I searched the cache, which meant that the program tried to send the entire video when a small portion was requested, which made the player close the connection. That was fixed by adding this method to MainClass
static bool TryGetRange (string url, out string range)
{
int index = url.IndexOf ("&range=");
if (index == -1) {
range = null;
return false;
}
index += 7;
int len = url.IndexOf ('&',index) - index;
range = url.Substring (index,len);
return true;
}
This method checks if the range parameter is present in the url, and then gets the value of it.
Then adding this code before if(File.Exists (requestData.Signature + "_done"))
string range;
if(TryGetRange (requestString, out range))
{
requestData.Signature += range;
}
This adds the range to the signature if the range parameter is detected