Bukkit ScoreBoard Acting Weird - java

I have a score board like so :
int time = 15;
private ScoreboardManager sbManager;
private Scoreboard scoreBoard;
private Objective obj;
private Score s0;
public void init(Player player) {
sbManager = Bukkit.getScoreboardManager();
scoreBoard = sbManager.getNewScoreboard();
obj = scoreBoard.registerNewObjective("ScoreBoard", "dummy");
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
obj.setDisplayName("Test");
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time = " + time));
s0.setScore(6);
player.setScoreboard(scoreBoard);
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable(){
public void run() {
time--;
updateScoreBoard(player);
System.out.println(time);
}
},20, 20);
}
And whenever I try to update it, it just dosen't work and btw my score board is a "fancy" one, so it should look like :
Time = time 6 <- the '6' is the default minecraft score.
Here's an example of my update method:
public void updateScoreBoard(Player p){
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time =" + time));
s0.setScore(6);
p.setScoreboard(scoreBoard);
}

Because you're using scoreboards in an unconventional way, things are bound to get tricky. By "fancy" I assume you mean the scoreboards which display a score's name and value right next to each other on the left side, which is done by placing the actual score value inside the name String of the score (like you have already done).
The problem with your code specifically is that you are not actually changing the value of the existing score entry (since that value is set to 6 to keep the entry in the same row of the display) but creating a new score entry every time you update the display, since score entries are identified by their name and not their score value (this is required so that different score entries can have the same value, for example a player can have a "bank balance" score with a value of 2 and an "amount of deaths" score with a value of 2).
If this weren't the case for example, your new score entry with name "Time = 14" and a score value of 6 would override the previous score entry with name "Time = 15" because of the identical score value, but this is not the case.
When I tested your code snippet, more rows (score entries) were added until the display filled to maximum capacity. I can only assume this is what you meant by your code "acting weird" since you didn't elaborate on the expected and observed results of your code.
You'll want to remove the previous score entry with the outdated value. Because the API is not intended to be used this way, one cannot simply remove a score entry from an objective (resetting the score doesn't remove the entire entry).
You'll therefore need to create a new scoreboard with a new objective etc. every time you want to update a single "fancy" score entry. This also means that all scores displayed in the scoreboard need to be kept track of independently and re-added and re-set to the new scoreboard whenever any other "fancy" score is updated.
These changes to your updateScoreboard method did the trick for me:
public void updateScoreBoard(Player p) {
scoreBoard = sbManager.getNewScoreboard();
obj = scoreBoard.registerNewObjective("ScoreBoard", "dummy");
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
obj.setDisplayName("Test");
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time = " + time));
s0.setScore(6);
p.setScoreboard(scoreBoard);
}
Note that this method only fixes the immediate issue of more entries being added, if you want more "fancy" and possibly even normal score entries, all of those will need to be handled respectively.
All this extra work and having meaningless numbers/values always on the right of the display seem like a large trade-off just to remove a little whitespace between a score's name and value.
Some other tips: You don't need to update the sbManager variable every time you initiate the scoreboard for a new player, the manager is always the same object, so using Bukkit.getScoreboardManager() once should suffice.

Related

Adding values to int from Array List

I am working on a personal project to create a game.
My trouble I seem to be running into is getting my variable called runs to increase value.
I have set my value to zero. I tried using runs++ though it only increases by one.
What I am looking to do is increase by 1 or 6 depending on the result of the if statement.
If anyone can point in the right direction on how to solve would be great!
public class BatsmanDice {
public static void rollBatsmanDice() {
// Roll player dice decides how many runs are scored when the player rolls.
// We have options from 1 to 6 and Owzthat.
// When Owzthat is triggered we return to the main method and run rollUmpireDice();
// Using an Array list to have all options available.
ArrayList batsmanDiceOptions = new ArrayList();
batsmanDiceOptions.add(1);
batsmanDiceOptions.add(2);
batsmanDiceOptions.add(3);
batsmanDiceOptions.add(4);
batsmanDiceOptions.add(5);
batsmanDiceOptions.add(6);
batsmanDiceOptions.add("Owzthat");
int runs = 0;
System.out.println("Total runs " + runs);
// We take our Array list from above and shuffle it using the Collections import tool.
Collections.shuffle(batsmanDiceOptions);
// We then take the shuffled array list and print 1 options to screen showing the dice rolled
// Commented out print line statement to return a random shuffled array option
//System.out.println(batsmanDiceOptions.get(1));
if (batsmanDiceOptions.contains(1)) {
System.out.println(" Scored 1 Run " + batsmanDiceOptions.get(1));
}
}
}
I'm not positive if this is what you're asking. But if you're trying to "roll" and increment runs, just do:
ArrayList<Integer> batsmanDiceOptions = new ArrayList<Integer>();
// your code
runs += batsmanDiceOptions.get(0);
To increment runs by some random value. get(0) returns a random value because you've already shuffled the ArrayList.
That being said... to simulate a dice roll, why not just increment by a random number from 1 to 6? I would recommend using ArrayList for things like picking finite items out of a hat, because then .remove() becomes useful. For dice rolls I would probably just use Random.

Using an String array element as a variable name?

I'm trying to import many pictures into a visible grid line to appear as a bar (of health, to be exact) that will decrease (adds a white image in place of bar's placement) when damage is taken. So I decide instead of writing out chucks of code for each of the 10 possible health point (not to mention there are other player stats that will be done in the same format), I decided upon scraping together a "for" loop with two if-else statements to attempt a loop to fill each grid element as long as the health value is greater than the "for" loop's "i". There is a slightly different image if the player happens to max their health at 10, hence the second "if-else" loop needed.<p>
My main question concerns the name of my loop, for I used an array to act as a kind of holder for string names that I wished to become the ImageIcon names, yet I've failed to either arrange the code properly or find a source explaining how one would go about using an array string name as the name for an ImageIcon.
Here is the loops and data:<p>
String[] array1 ={"hOne","hTwo","hThree","hFour","hFive","hSix","hSeven","hEight","hNine","hTen"};
String tempY = " ", tempN = " ", tempF = " ", tempNF = " ";
//row 1, health
statsPanel.add(stat1);
for (int i=0; i<=9; i++){
if ((i+1)<heal){
tempY=array1[i];
ImageIcon tempY = new ImageIcon("C:\\Users\\Kunkle\\hea.png");
ColorPanel tempYz = new ColorPanel(Color.black, tempY);
statsPanel.add(tempYz);
}
else {
tempN=array1[i];
ImageIcon tempN = new ImageIcon("C:\\Users\\Kunkle\\non.png");
ColorPanel tempNz = new ColorPanel(Color.black, tempN);
statsPanel.add(tempNz);
}
if (i==8 && heal==10){
tempF=array1[i];
ImageIcon tempF = new ImageIcon("C:\\Users\\Kunkle\\shea.png");
ColorPanel tempFz = new ColorPanel(Color.black, tempF);
statsPanel.add(tempFz);
}
else {
tempNF=array1[i];
ImageIcon tempNF = new ImageIcon("C:\\Users\\Kunkle\\shea.png");
ColorPanel tempNFz = new ColorPanel(Color.black, tempNF);
statsPanel.add(tempNFz);
}
}
Everything has been properly declared variable and import-wise, and the only 3 errors I get is the four lines where the array element is is stated after the first "ImageIcon" in each declaration of a new image. Does there happen to be a way to keep code short with a "for" loop (or several) but still bring in an image under a new name for every pass?
You cannot do what you are attempting to do. Java is not a dynamic language that can substitute variable values for names, a la Perl where $x="a"; $$x=3; results in variable $a having the value 3.
The closest thing you can do is use a Map<String,ImageIcon> to associate strings with objects. If you want to associate both an ImageIcon and ColorPanel with a name you would need a wrapper object to hold references to both, and you have a Map<String,MyWrapper> instead.
I would provide a code sample but that would require seeing the code of statsPanel, which you haven't provided. My guess is statsPanel would be (or contain) the Map<> I mentioned above.

Using nested loops

I'm really struggling to do this! z is an array of gravitational fields. To find the total gravitational field acting on a planet, say earth, I want to add all the entries together, while excluding the entry for earth's gravitational field, because earth's gravity doesn't act on earth itself.
For example, say z = [earthGrav, sunGrav, marsGrav, moonGrav]. Then the total field on earth is sunGrav+ marsGrav + moonGrav. I could maybe deal with this by using s=i+1. But that doesn't work subsequently, for the sun, when sunGrav = earthGrav+marsGrav+moonGrav, because the first entry would be left out!
for(int i=0; i<planets.length;i++){
for(int s=0;s<z.length;s++){
if(i!=s){
sum1.increaseBy(z[s]);
newP[i] = planets[i].updatePosition(position[i], velocity[i], timeStep, sum1);
}
else{
sum1.scale(1);
}
}
}
Problem is, the way I've done it above means whenever I add 1 to i, 1 also gets added to s, so s and i are always the same and the if statement never gets executed! Can anyone think of a way to do this?

Adding a several random numbers to graphics context above images

I am creating a old school game where the user has to collect the falling objects. Currently I have an image that is printed to the GraphicsContext several times accross the pane and is added and removed from an arrayList() when it disappears off of the screen. I can create a random number and I can print this to the same position as the falling image. However the random number is always the same and I want the number to be different on each of the objects. My code in my start method is as follows:
int i;
for(i=0;i<800; i+=90)
arrayList.add(new Object(ImageView, noOnImage, i,-10));
I then also have an update method where the objects are continously redrawn:
int newObject = 0;
Iterator<Object> objectIterator = object.iterator();
while(objectIterator.hasNext())
{
Object ob = objectIterator.next();
if(ob.move())
{
objectIterator.remove();
newObject++;
}
gc.drawImage(ob.objectImage,ob.r.getX(), ob.r.getY(), ob.r.getWidth(),
ob.r.getHeight());
gc.fillText(String.valueOf(noOnImage), ob.r.getX()+8, ob.r.getY()+22);
}
noOneImage is just a randomly generated number that I declared at the top. I would like each object to contain a different random value, currently they are all the same though, even though it is random.
When you create the object, pass in the random number within your loop.
Random rand = new Random()
arrayList.add(new Object(ImageView, noOnImage, i,-10, rand.nextInt(0, 10)));
That rand will give you a number between 0 and 10. You can put whatever int you want in there.
And make sure the object you create has the field and you are able to retrieve this number (e.g. for a score tally, etc.).

Trying to get a random element from an array so that I can mark it as "booked"

This is what I have in my method to randomly select a element in my array, however I'm not sure why it isn't working, I feel like I have tried every way of writing it, any ideas.
public static Seat BookSeat(Seat[][] x){
Seat[][] book = new Seat[12][23];
if (x != null){
book = x[(Math.random()*x.length)];
}
return book;
}
The way you explain things makes me think a couple of concepts somehow got crosswired. I am assuming that book is some (2 dimensional) array of Seat objects from which you want to pick a random one. In order to do so, you need to specify a random choice for each dimension of the array:
// this should be declared elsewhere because if it's local to bookSeat it will be lost
// and reinitialized upon each call to bookSeat
Seat[][] book = new Seat[12][23];
// and this is how, after previous declaration, the function will be called
Seat theBookedSeat = bookSeat(book);
// Okay, now we have selected a random seat, mark it as booked, assuming Seat has a
// method called book:
theBookedSeat.book();
// and this is the modified function. Note also that function in Java by convention
// start with a lowercase letter.
public static Seat bookSeat(Seat[][] x){
if (x != null){
// using Random as shown by chm052
Random r = new Random();
// need to pick a random one in each dimension
book = x[r.nextInt(x.length)][r.nextInt(x[0].length)];
}
return book;
}
You should also integrate a test to check whether the selected seat was already booked and repeat the selection:
do {
// need to pick a random one in each dimension
book = x[r.nextInt(x.length)][r.nextInt(x[0].length)];
while (book.isBooked()); // assuming a getter for a boolean indicating
// whether the seat is booked or not
But a full-random selection like this has a couple of disadvantages:
the selection being random, you can repeatedly fall on already booked seats, and the chances that happens increase with the number of already booked seats. But even with few booked seats you could be really unlucky and see the loop spin around tens of times before it hits an unbooked seat.
you should absolutely test whether there are still unbooked seats left before entering the loop or it will spin indefinitely.
Therefore it might be a good idea to implement a smarter selection routine, eg by randomly picking a row and a seat and start searching from there until the first free seat is encountered, but for first steps this one should do just fine.
I hope this is what you wanted to achieve, if not feel free to comment and allow me to correct and adapt.
Floor the number returned by the (Math.random()*x.length) expression.
Math.floor(Math.random()*x.length);
At the moment, you're trying to subscript the array with a floating point number.
The other answer will totally work, but here is another way of doing it using Random.nextInt() if you don't want to have to do all the mathing around:
Random r = new Random();
book = x[r.nextInt(x.length)];
It uses java.util.Random, so make sure you import that if you do this.

Categories