How to print only unique names here in photon network unity - unity3d

I did this but it prints one name multiple times. How do I make sure it prints one name only one at a time:
foreach(Player player in PhotonNetwork.PlayerList)
{
if(race_entered)
{
for(int i = 0; i <= PhotonNetwork.PlayerList.Length; i++)
{
player_name[i].text = player.NickName;
}
}
}

You are currently iterating exponentially. For every player you again iterate all players and overwrite all UI texts with the current player.
What you want is iterating only once
if(race_entered)
{
// cache since property access might be expensive
var players = PhotonNetwork.PlayerList;
// Note btw for iterating collections you always want an index
// "< Length" instead of "<= Length"
for(int i = 0; i < players.Length; i++)
{
var player = players[i];
player_name[i].text = player.NickName;
}
}

Related

How to fix : The object of type 'GameObject' has been destroyed but you are still trying to access it ? -Unity

I made a 5 second time bar to replace the wave. when wave1 has been 5 seconds it will move to wave2. then the first wave will be destroyed. when I got to wave3, an error came out. here's my code:
IEnumerator ChangeWave()
{
for (int i = 0; i < wave.Length - 1; i++)
{
yield return new WaitForSeconds(5f);
Destroy(wave[i]);
wave[i+1].SetActive(true);
}
}
the error said The object of type 'GameObject' has been destroyed but you are still trying to access it. - unity
sorry for my bad english.
There's a few things going on here.
Remove the -1 in the for loop, so it iterates to end
wave[i+1] will cause an error, so check if (i < wave.Length -1)
Destroy( array[index] ) will try and access Game Object but it's destroyed, so you should create a temporary var to hold gameobject, and set null to the array element.
Some fixes below - there might be a better way, but this is what I use:
Version 1 - Using the above fixes
IEnumerator ChangeWaveV2()
{
for (int i = 0; i < wave.Length; i++)
{
yield return new WaitForSeconds(.2f);
var t = wave[i];
wave[i] = null;
Destroy(t);
if(i < wave.Length - 1)
wave[i + 1].SetActive(true);
}
}
Version 2 - A variation without needing to null out the element and create a temporary var. If you iterate from end to front of the array, you can freely Destroy() GameObjects in an array. May not be useful as it changes the wave array.
IEnumerator ChangeWaveV3()
{
System.Array.Reverse(wave);
for (int i = wave.Length - 1; i >= 0; i--)
{
yield return new WaitForSeconds(.2f);
Destroy(wave[i]);
if(i > 0)
wave[i - 1].SetActive(true);
}
}

Unity / Search closes Object from a List by tag

I have a Problem to find the closest Object in my List.
There are three types with the tags (Food, Stone and Wood).
I spawn them at the beginning , some for each type, if i found some Resources, they're not hidden anymore, and i add them to the List that a Worker goes to them and harvests them.
So Later in the Game, for expample
i found 3 Stone Resources, then worker should harvest the closest one first everytime....
but i don't know how to iterate throw a Loop only to search for the Tags and how to get the position of the closest one.
Here is some code of the Method that i wrote:
void FindNearestFoodRessource()
{
for (int i = 0; i < gameController.discoveredRessources.Count; i++)
{
//float dist = Vector3.Distance(gameController.discoveredRessources[i].transform.position, transform.position);
GameObject nearestFoodRessource = GameObject.FindGameObjectWithTag("Food");
}
}
First thing first - don't use FindGameObject**** in frequently called methods, it is very expensive.
About your problem - just check tag and distance of all the resources:
float minDist = Vector3.Distance(gameController.discoveredRessources[0].transform.position, transform.position);
int minDistIndex = 0;
for (int i = 1; i < gameController.discoveredRessources.Count; i++)
{
if (gameController.discoveredRessources[i].gameObject.CompareTag("Food"))
{
float dist = Vector3.Distance(gameController.discoveredRessources[i].transform.position, transform.position);
if (dist < minDist)
{
minDist = dist;
minDistIndex = i;
}
}
}
//Now you can move to gameController.discoveredRessources[minDistIndex]
Also you can store all the food/stones/wood in the separate lists when you find it
Using Linq Where and this usefull extension method MinBy
using System;
using System.Collections.Generic;
using System.Linq;
public static class Linqextensions
{
public static T MinBy<T, R>(this IEnumerable<T> en, Func<T, R> evaluate) where R : IComparable<R>
{
return en.Select(t => new Tuple<T, R>(t, evaluate(t)))
.Aggregate((max, next) => next.Item2.CompareTo(max.Item2) < 0 ? next : max).Item1;
}
}
(simply copy that code somwhere into your project) you could do it in "one" line
var closestItem = gameController.discoveredRessources
// this is a filter only selecting the ones with tag = "Food"
.Where(obj => obj.CompareTag("Food"))
// this returns you the item from the list with the lowest distance
.MinBy(obj => Vector3.Distance(obj.transform.position, transform.position));

Is it necessary to create <span> elements to register event listeners

I have a working web app that reads local .txt files and displays the content in a div element. I create a span element out of each word because I need to be able to select any word in the document and create an EEI (Essential Elements of Information) from the text. I then register a click handler on the containing div and let the event bubble up. The three functions below show reading the file, and parsing it, and populating the text div with spans:
function readInputFile(evt) {
reset();
var theFile = evt.target.files[0];
if(theFile) {
$("#theDoc").empty(); //Clean up any old docs loaded
var myReader = new FileReader();
var ta = document.getElementById("theDoc");
myReader.onload = function(e) {
parseTheDoc(e.target.result);
initialMarkup();
};
myReader.readAsText(theFile);
} else {
alert("Can not read input file: readInputFile()");
}
}
function parseTheDoc(docContents) {
var lines = docContents.split("\n");
var sentWords =[];
for(var i = 0; i < lines.length; i++) {
sentWords = lines[i].split(" ");
words = words.concat(sentWords);
words.push("<br>");
}
//examineWords(words);
createSpans(words);
}
function createSpans() {
for (var i = 0; i < words.length; i++) {
var currentWord = words[i];
if(currentWord !== "<br>") {
var $mySpan = $("<span />");
$mySpan.text(currentWord + " ");
$mySpan.attr("id", "word_" + i);
$("#theDoc").append($mySpan);
buildDocVector(currentWord, i, $mySpan);
}
else {
var $myBreak = $("<br>");
$myBreak.attr("id", "word_" + i);
$("#theDoc").append($myBreak);
buildDocVector("br", i, $myBreak);
}
}
//console.log("CreateSpans: Debug");
}
So basically a simple fileReader, split on \n, then tokenize on white space. I then create a span for each word, and a br element for each \n. It's not beautiful, but it satisfies the requirement, and works. My question is, is there a more efficient way of doing this? It just seems expensive to create all these spans, but my requirement is to annotate the doc and map any selected word to a data model/ontology. I can't think of a way to allow the user to select any word, or combination of words (control click) and then perform operations on them. This works, but with large docs (100 pages) I start having performance/memory issues. I understand this is more a design question and may not be appropriate, but I'd really like to know if there are more performant solutions.

Manatee.Trello Moving Cards

I'm writing a small application to manage Trello Boards in only a few aspects such as sorting Cards on a List, moving/copying Cards based on Due Date and/or Labels, archiving Lists on a regular basis and generating reports based on Labels, etc. As such, I've been putting together a facade around the Manatee.Trello library to simplify the interface for my services.
I've been getting comfortable with the library and things have been relatively smooth. However, I wrote an extension method on the Card class to move Cards within or between Lists, and another method that calls this extension method repeatedly to move all Cards from one List to another.
My issue is that when running the code on a couple of dummy lists with 7 cards in one, it completes without error, but at least one card doesn't actually get moved (though as many as 3 cards have failed to move). I can't tell if this is because I'm moving things too rapidly, or if I need to adjust the TrelloConfiguration.ChangeSubmissionTime, or what. I've tried playing around with delays but it doesn't help.
Here is my calling code:
public void MoveCardsBetweenLists(
string originListName,
string destinationListName,
string originBoardName,
string destinationBoardName = null)
{
var fromBoard = GetBoard(originBoardName); // returns a Manatee.Trello.Board
var toBoard = destinationBoardName == null
|| destinationBoardName.Equals(originBoardName, StringComparison.OrdinalIgnoreCase)
? fromBoard
: GetBoard(destinationBoardName);
var fromList = GetListFromBoard(originListName, fromBoard); // returns a Manatee.Trello.List from the specified Board
var toList = GetListFromBoard(destinationListName, toBoard);
for (int i = 0; i < fromList.Cards.Count(); i++)
{
fromList.Cards[i].Move(1, toList);
}
}
Here is my extension method on Manatee.Trello.Card:
public static void Move(this Card card, int position, List list = null)
{
if (list != null && list != card.List)
{
card.List = list;
}
card.Position = position;
}
I've created a test that replicates the functionality you want. Basically, I create 7 cards on my board, move them to another list, then delete them (just to maintain initial state).
private static void Run(System.Action action)
{
var serializer = new ManateeSerializer();
TrelloConfiguration.Serializer = serializer;
TrelloConfiguration.Deserializer = serializer;
TrelloConfiguration.JsonFactory = new ManateeFactory();
TrelloConfiguration.RestClientProvider = new WebApiClientProvider();
TrelloAuthorization.Default.AppKey = TrelloIds.AppKey;
TrelloAuthorization.Default.UserToken = TrelloIds.UserToken;
action();
TrelloProcessor.Flush();
}
#region http://stackoverflow.com/q/39926431/878701
private static void Move(Card card, int position, List list = null)
{
if (list != null && list != card.List)
{
card.List = list;
}
card.Position = position;
}
[TestMethod]
public void MovingCards()
{
Run(() =>
{
var list = new List(TrelloIds.ListId);
var cards = new List<Card>();
for (int i = 0; i < 10; i++)
{
cards.Add(list.Cards.Add("test card " + i));
}
var otherList = list.Board.Lists.Last();
for(var i = 0; i < cards.Count; i++)
{
Move(card, i, otherList);
}
foreach (var card in cards)
{
card.Delete();
}
});
}
#endregion
Quick question: Are you calling TrelloProcessor.Flush() before your execution ends? If you don't, then some changes will likely remain in the request processor queue when the application ends, so they'll never be sent. See my wiki page on processing requests for more information.
Also, I've noticed that you're using 1 as the position for each move. By doing this, you'll end up with an unreliable ordering. The position data that Trello uses is floating point. To position a card between two other cards, it simply takes the average of the other cards. In your case, (if the destination list is empty), I'd suggest sending in the indexer variable for the ordering. If the destination list isn't empty, you'll need to calculate a new position based on the other cards in the list (by the averaging method Trello uses).
Finally, I like the extension code you have. If you have ideas that you think would be useful to add to the library, please feel free to fork the GitHub repo and create a pull request.

ID element to not display

I have this code:
function showForm()
{
var a=document.getElementById("opts").value;
if(a==1)
{
document.getElementById("f1").style.display="block";
document.getElementById("f2").style.display="none";
document.getElementById("f3").style.display="none";
document.getElementById("f4").style.display="none";
document.getElementById("f5").style.display="none";
document.getElementById("f6").style.display="none";
document.getElementById("f7").style.display="none";
document.getElementById("f8").style.display="none";
document.getElementById("f9").style.display="none";
document.getElementById("f10").style.display="none";
document.getElementById("f11").style.display="none";
document.getElementById("f12").style.display="none";
document.getElementById("f13").style.display="none";
document.getElementById("f14").style.display="none";
document.getElementById("f15").style.display="none";
document.getElementById("f16").style.display="none";
document.getElementById("f17").style.display="none";
document.getElementById("f18").style.display="none";
document.getElementById("f19").style.display="none";
document.getElementById("f20").style.display="none";
document.getElementById("f21").style.display="none";
document.getElementById("f22").style.display="none";
document.getElementById("f23").style.display="none";
document.getElementById("f24").style.display="none";
document.getElementById("f25").style.display="none";
document.getElementById("f26").style.display="none";
document.getElementById("f27").style.display="none";
document.getElementById("f28").style.display="none";
document.getElementById("f29").style.display="none";
document.getElementById("f30").style.display="none";
document.getElementById("f31").style.display="none";
document.getElementById("f32").style.display="none"
}
if(a==2)
{
//...
}
}
Is it possible to get this js to be smaller?
I use it for the website www.borrani.com in the double dropdown selector
A loop could certainly make it smaller:
for (var i = 1; i <= 32; i++) {
document.getElementById('f' + i).style.display = 'none';
}
document.getElementById('f1').style.display = 'block';
You might even try querySelectorAll to explicitly identify your elements based on a pattern, assuming you can define a unique pattern for only the elements you want:
var elements = document.querySelectorAll('[id^="f"]');
for (var i = 0; i < elements.length; i++) {
elements[i].style.display = 'none';
}
document.getElementById('f1').style.display = 'block';
It may be slightly more code, but it de-couples the code from the specific number of elements being identified.