I'm creating a plugin for an event, this event is just: when you stop moving, you loose. I created everything, but my check to know if a player moves or not doesn't work:
I tried to make an array and when a player move event it's added, but it doesn't work,
#EventHandler
public static void OnPlayerMoov(PlayerMoveEvent e) {
if(!playerHaveMooved.contains(e.getPlayer())) {
playerHaveMooved.add(e.getPlayer());
}
}
public static boolean isMoving(Player p){
System.out.println(Respawn.playerHaveMooved.contains(p));
return Respawn.playerHaveMooved.contains(p);
}
I tried to use velocity; it doesn't work,
public static boolean isMoving(Player p){
return (p.getVelocity().length() == 0);
}
It doesn't work. It kills me when I am moving.
Do you have a solution?
The first don't work because you just check if the player already move a time, which will always be true.
The second about velocity check only if player get knockbacked for example.
First solution
Save last time of move, and check each few time if it stop move.
In this example, I will force player to move each seconds.
private final HashMap<Player, Long> timeMove = new HashMap<>(); // map for data
#Eventhandler
public void onMove(PlayerMoveEvent e) {
timeMove.put(e.getPlayer(), System.currentTimeMillis()); // update last move
}
public void startChecking(JavaPlugin pl) {
pl.getServer().getScheduler().runTaskTimer(pl, () -> {
long current = System.currentTimeMillis();
for(Player p : Bukkit.getOnlinePlayers()) {
long last = timeMove.getOrDefault(p, 0);
long diff = current - last;
if(diff > 1000) { // 1000 = second
// player don't move
}
}
}, 20, 20);
}
Second solution
Check each X time from last and current location
private final HashMap<Player, Location> lastLoc = new HashMap<>(); // map for data
public void startChecking(JavaPlugin pl) {
pl.getServer().getScheduler().runTaskTimer(pl, () -> {
for(Player p : Bukkit.getOnlinePlayers()) {
Location lastPlayerLoc = lastLoc.get(p); // get loc, or keep null if not registered
if(lastPlayerLoc != null) {
double distance = lastPlayerLoc.distance(p.getLocation());
if(distance == 0.0) {
// here the player don't move
continue; // go to next player
}
}
lastLoc.put(p, p.getLocation()); // update loc
}
}, 20, 20);
}
I'm making a simple procedural generated dungeon where your character spawns in a room with randomly opened or closed doors in random direction. This is already complete.
When the character leaves the room it will generate new random numbers for a new room. Storing the numbers of the old room and to generate a room with those numbers if the character travels backwards. This part isn't finished, but would be easy to do, but I don't want to do that yet, because it will cause the problem below.
How could I create something that could store that no matter where the player travels and know when to use the variables? How could I automatically create variables like that?
Current Code:
public class Executable extends JFrame implements KeyListener {
Container contentPane=this.getContentPane();
Graphics bufferGraphics;
int xAxis; //Universal Variables:
int yAxis;
int characterX=463;
int characterY=486;
int oldCharacterX=463;
int oldCharacterY=486;
Image characterNorth = CustomImages.createImageIcon("Images/characterNorth.jpg").getImage();
Image characterEast = CustomImages.createImageIcon("Images/characterEast.jpg").getImage();
Image characterSouth = CustomImages.createImageIcon("Images/characterSouth.jpg").getImage();
Image characterWest = CustomImages.createImageIcon("Images/characterWest.jpg").getImage();
Image brickWall = CustomImages.createImageIcon("Images/brickWall.jpg").getImage();
Image brickFloor = CustomImages.createImageIcon("Images/brickFloor.jpg").getImage();
Image character=characterNorth;
boolean pressed=false;
static boolean northDoor;
static boolean eastDoor;
static boolean southDoor;
static boolean westDoor;
static boolean Randomizer=true;
static int north;
static int east;
static int south;
static int west;
static Random r=new Random();
boolean doorOpen=false;
public static void main(String[] args) { //Main
north=r.nextInt(3)+1;
east=r.nextInt(3)+1;
south=r.nextInt(3)+1;
west=r.nextInt(3)+1;
if(north==1) {
northDoor=true;
}else {
northDoor=false;
}
if(east==1) {
eastDoor=true;
}else {
eastDoor=false;
}
if(south==1) {
southDoor=true;
}else {
southDoor=false;
}
if(west==1) {
westDoor=true;
}else {
westDoor=false;
}
Executable e=new Executable();
}
public Executable() { //Canvas
this.setBounds(0, 0, 1680, 1050);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addKeyListener(this);
setFocusable(true);
requestFocusInWindow();
}
public void paint(Graphics g) { //Paint
for(xAxis=58;xAxis<=858;xAxis=xAxis+50) {
for(yAxis=81;yAxis<=881;yAxis=yAxis+50) {
g.drawImage(brickFloor,xAxis,yAxis,null);
}
yAxis=31;
}
for(xAxis=8;xAxis<958;xAxis=xAxis+50) {
g.drawImage(brickWall,xAxis,yAxis,null);
}
yAxis=931;
for(xAxis=8;xAxis<=908;xAxis=xAxis+50) {
g.drawImage(brickWall,xAxis,yAxis,null);
}
xAxis=8;
for(yAxis=81;yAxis<=881;yAxis=yAxis+50) {
g.drawImage(brickWall,xAxis,yAxis,null);
}
xAxis=908;
for(yAxis=81;yAxis<=881;yAxis=yAxis+50) {
g.drawImage(brickWall,xAxis,yAxis,null);
}
while(!doorOpen) {
if(northDoor==false && eastDoor==false && southDoor==false && westDoor==false) {
north=r.nextInt(3)+1;
east=r.nextInt(3)+1;
south=r.nextInt(3)+1;
west=r.nextInt(3)+1;
if(north==1) {
northDoor=true;
}else {
northDoor=false;
}
if(east==1) {
eastDoor=true;
}else {
eastDoor=false;
}
if(south==1) {
southDoor=true;
}else {
southDoor=false;
}
if(west==1) {
westDoor=true;
}else {
westDoor=false;
}
}else {
doorOpen=true;
}
}
if(northDoor) {
g.drawImage(brickFloor,458,31,null);
}
if(eastDoor) {
g.drawImage(brickFloor,908,481,null);
}
if(southDoor) {
g.drawImage(brickFloor,458,931,null);
}
if(westDoor) {
g.drawImage(brickFloor,8,481,null);
}
g.drawImage(character,characterX,characterY,null);
}
#Override
public void keyPressed(KeyEvent arg0) { //Character rotation and movement.
if(pressed==false) {
pressed=true;
if(arg0.getKeyCode() == KeyEvent.VK_W){
if(character==characterNorth) {
if(characterY>86 && characterX>13 && characterX<913) {
characterY=characterY-50;
}else if(northDoor && characterX==463) {
oldCharacterY=characterY;
characterY=characterY-50;
}
}else {
character=characterNorth;
}
}
if(arg0.getKeyCode() == KeyEvent.VK_A){
if(character==characterWest && characterY>36 && characterY<926) {
if(characterX>63) { //and y is greater than and less than
oldCharacterX=characterX;
characterX=characterX-50;
}else if(westDoor && characterY==486) {
oldCharacterX=characterX;
characterX=characterX-50;
}
}else {
character=characterWest;
}
}
if(arg0.getKeyCode() == KeyEvent.VK_S){
if(character==characterSouth) {
if(characterY<871 && characterX>13 && characterX<913) {
oldCharacterY=characterY;
characterY=characterY+50;
}else if(southDoor && characterX==463) {
oldCharacterY=characterY;
characterY=characterY+50;
}
}else {
character=characterSouth;
}
}
if(arg0.getKeyCode() == KeyEvent.VK_D){
if(character==characterEast && characterY>36 && characterY<926) {
if(characterX<848) { //and y is greater than and less than
oldCharacterX=characterX;
characterX=characterX+50;
}else if(eastDoor && characterY==486) {
oldCharacterX=characterX;
characterX=characterX+50;
}
}else {
character=characterEast;
}
}
repaint(oldCharacterX,oldCharacterY,40,40);
repaint(characterX,characterY,40,40);
}
}
#Override
public void keyReleased(KeyEvent arg0) { //Prevents keys from being held down.
if(arg0.getKeyCode() == KeyEvent.VK_W){
pressed=false;
}
if(arg0.getKeyCode() == KeyEvent.VK_A){
pressed=false;
}
if(arg0.getKeyCode() == KeyEvent.VK_S){
pressed=false;
}
if(arg0.getKeyCode() == KeyEvent.VK_D){
pressed=false;
}
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
Hopefully this will help a bit. I would suggest you have a game state, this handles drawing, moving, key events like your current Executable class.
Basic overview of what is below. The GameState has a reference to a currentRoomState this is what you should deem the character is in. Upon moving to a door, you will need to check for this, the call to currentRoomState.MoveToNextRoom() with the appropreate parameters.
This will trigger the current room state to generate a new room, set the reference to the new room to be tied to the correct door, place the character at the correct door in the new room, tie a refernce to the old room in the new room and set the current room to the new room.
When you move to a door that has a previous room tied to it, the variables will have been persisted.
Best of luck
-Chris
eg:
class GameState{
RoomState startingRoomState = new RoomState();
RoomState currentRoomState = startingRoomState;
public void move(int x, int y)
{
currentRoomState.iCharacterPosX += x;
currentRoomState.iCharacterPosY += y;
// Check if need to move to a new room (eg move north)
currentRoomState = currentRoomState.MoveToNextRoom(true, false, false, false);
}
public void draw()
{
//Based on the character pos and draw variables in currentRoomState
}
}
And then you have a room state, which describes a room
class RoomState{
//Where the doors are
boolean northDoor = false;
boolean eastDoor = false;
boolean southDoor = false;
boolean westDoor = false;
// Reference to the room adjacent rooms
RoomState rs_NorthDoor = null;
RoomState rs_EastDoor = null;
RoomState rs_SouthDoor = null;
RoomState rs_WestDoor = null;
int iCharacterPosX = 0;
int iCharacterPosY = 0;
// Initial
RoomState(){
northDoor = true; eastDoor = true; southDoor = true; westDoor = true;
}
RoomState(RoomState prevState, boolean north, boolean east, boolean south, boolean west){
// Randomise door states
// Put character in the position he should be
iCharacterPosX = 0;//right most x Coord - oldX
iCharacterPosX = 0;//bottom most y Coord - oldy
if(north)
{
rs_NorthDoor = prevState;
} //elseif other doors
}
public RoomState MoveToNextRoom(boolean north, boolean east, boolean south, boolean west){
if(north){
if(rs_NorthDoor == null)
{
rs_NorthDoor = new RoomState(this, north, east, south, west);
}
return rs_NorthDoor;
} //else if the others
return null;
}
}
If you are looking to store the random number associated with each room and then traverse backward, in order, through the random numbers, a stack is the data structure you are looking for. To gain a conceptual understanding of a stack, see Stack (abstract data type). In short, a stack is like a pile of papers, where the last item placed at the top of the pile is the first element removed from the pile when traversing through the papers, termed Last-in-First-out (LIFO) ordering.
In Java, a Deque (double-ended queue, pronounced "deck") can be used as a stack. To put an element on the top of the stack, you use the push method and remove an element from the top of the stack, you use the pop method (note that pop both obtains the value at the top of the stack and removes it from the stack). For example:
Deque<Integer> stack = new ArrayDeque<>();
stack.push(10);
stack.push(20);
System.out.println(stack.pop());
stack.push(30);
System.out.println(stack.pop());
System.out.println(stack.pop());
This code will produce the following output:
20
30
10
To encapsulate this functionality, you can create a new class called RoomTracker (or something similarly named to denote the action of tracking the previous rooms) and implement it as follows:
public class RoomTracker {
private final Deque<Integer> rooms = new ArrayDeque<>();
public void addRoomNumber(Integer roomNumber) {
rooms.push(roomNumber);
}
public Integer getPreviousRoomNumber() {
return rooms.pop();
}
}
In a similar fashion as before, you can use this code as follows:
RoomTracker tracker = new RoomTracker();
tracker.addRoomNumber(10);
tracker.addRoomNumber(20);
System.out.println(tracker.getPreviousRoomNumber());
tracker.addRoomNumber(30);
System.out.println(tracker.getPreviousRoomNumber());
System.out.println(tracker.getPreviousRoomNumber());
This will produce the following output:
20
30
10
If you need to track the direction in which you entered the room (so that you find if a player is going to a previous room), you can create a class called Room and store the randomly generated number and the direction in which the player entered:
public enum Direction {
TOP, RIGHT, BOTTOM, LEFT;
}
public class Room {
private final int number;
private final Direction enteredFrom;
public Room(int number, Direction enteredFrom) {
this.number = number;
this.enteredFrom = enteredFrom;
}
public int getNumber() {
return number;
}
public Direction getEnteredFrom() {
return enteredFrom;
}
}
You can then redefine RoomTracker in terms of Room:
public class RoomTracker {
private final Deque<Room> rooms = new ArrayDeque<>();
public void addRoom(Room room) {
rooms.push(room);
}
public Room getPreviousRoom() {
return rooms.pop();
}
}
You can then push Room objects onto the stack as the player travels from one room to the next. For example:
RoomTracker tracker = new RoomTracker();
tracker.push(new Room(10, Direction.LEFT); // Travel right into room 10
tracker.push(new Room(20, Direction.TOP); // Travel down into room 20
I've got a BooleanBinding, which looks like this:
public void initQueue(ObservableList<Player> players) {
queueIsFree = new BooleanBinding() {
{
players.forEach(
player -> bind(player.getRobot().animatingProperty));
}
#Override
protected boolean computeValue() {
Boolean bool = true;
for (Player p : players) {
if (p.getRobot().animatingProperty.get() == true) {
bool = false;
break;
}
}
return bool;
}
};
}
It is supposed to be true, when all of the animatingProperties of the Robots are false. As soon as one of them changes, this changeListener is called:
change = new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> arg0,
Boolean oldValue, Boolean newValue) {
if (newValue.equals(true)) {
if (list.size() > 0) {
// plays the next animation, which, when finished, sets the animatingProperty back to false
nextAnimation();
} else {
stopQueue();
}
}
}
};
Problem: the valueChangedEvent fires so often, that i get a stackOverFlowError.
In order to animate, i use a TimeLine and an AnimationTimer, i suppose that this is the problem, yet i don't know how to solve it.
Edit: I know now, that the Problem is, that TimeLines are asynchronous, meaning, that they start and then the next line of code is executed, which means, that the booleanBinding, that i've created is useless.
I'll have to think of another way to play my animations one after another.
I'm trying to do a random method with BlueJ to play a random song of a playlist and then continue. My problem is that it just play one song and then stop. Here is my code. Hope someone can help me
https://gist.github.com/anonymous/9493432
My error is that all songs start simultaneously. Here is my code:
public void randomAllTracks(int index){
if(indexValid(index)) {
for(Track track : tracks) {
player.startPlaying(track.getFilename());
System.out.println("Now playing: " + track.getArtist() + " - " + track.getTitle());
System.out.println();
int randomTrack = (int)(Math.random() * tracks.size());
}
}
}
To get a random track that is always a valid index:
int randomTrack = (int)(Math.random() * tracks.size());
You can delete method randomTrack() because you don't need it.
You need some type of indication in class MusicPlayer to check whether the track is done. Here, this is represented by trackFinished. You can look at that variable as you play the song.
boolean trackFinished = true;
public void randomAllTracks(int index) {
while (true) {
if (trackFinished) {
playTrack((int)(Math.random() * tracks.size()));
trackFinished = false;
}
}
}
MusicPlayer code:
public class MusicPlayer
{
// The current player. It might be null.
private AdvancedPlayer player;
boolean finished = true;
//some code
public void startPlaying(final String filename)
{
try {
setupPlayer(filename);
Thread playerThread = new Thread() {
public void run()
{
try {
trackFinished = false;
player.play(5000);
}
catch(JavaLayerException e) {
reportProblem(filename);
}
finally {
killPlayer();
trackFinished = true;
}
}
};
playerThread.start();
}
catch (Exception ex) {
reportProblem(filename);
}
}
}
I have made a custom BasicScrollBarUI.
I have replaced the incrButton / decrButton by JLabels.
Therefore i had to override the InstallListeners(), to add the Listener to the incr/decrLabel instead of the JButtons.
//TODO
protected void installListeners() {
trackListener = createTrackListener();
buttonListenerCustom = createArrowButtonListenerCustom();
modelListener = createModelListener();
propertyChangeListener = createPropertyChangeListener();
scrollbar.addMouseListener(trackListener);
scrollbar.addMouseMotionListener(trackListener);
scrollbar.getModel().addChangeListener(modelListener);
scrollbar.addPropertyChangeListener(propertyChangeListener);
// scrollbar.addFocusListener(getHandler());
if (incrLabel != null) {
incrLabel.addMouseListener(buttonListenerCustom);
System.out.println("OK gemacht");
}
if (decrLabel != null) {
decrLabel.addMouseListener(buttonListenerCustom);
}
scrollListener = createScrollListener();
scrollTimer = new Timer(scrollSpeedThrottle, scrollListener);
scrollTimer.setInitialDelay(300); // default InitialDelay?
}
Therefore i had to override the ArrowButtonListener, to react on the Labels.
protected class ArrowButtonListenerCustom extends MouseAdapter {
boolean handledEvent;
public void mousePressed(MouseEvent e) {
if (!scrollbar.isEnabled()) {
return;
}
// not an unmodified left mouse button
// if(e.getModifiers() != InputEvent.BUTTON1_MASK) {return; }
if (!SwingUtilities.isLeftMouseButton(e)) {
return;
}
int direction;
if (e.getSource() == incrLabel) {
direction = 1;
incrLabel.setIcon(new ImageIcon(increaseButtonPressedImage));
} else {
direction = -1;
decrLabel.setIcon(new ImageIcon(decreaseButtonPressedImage));
}
scrollByUnit(direction);
scrollTimer.stop();
scrollListener.setDirection(direction);
scrollListener.setScrollByBlock(false);
scrollTimer.start();
handledEvent = true;
if (!scrollbar.hasFocus() && scrollbar.isRequestFocusEnabled()) {
scrollbar.requestFocus();
}
}
public void mouseReleased(MouseEvent e) {
scrollTimer.stop();
handledEvent = false;
scrollbar.setValueIsAdjusting(false);
incrLabel.setIcon(new ImageIcon(increaseButtonImage));
decrLabel.setIcon(new ImageIcon(decreaseButtonImage));
}
}
Of course createArrowButtonListenerCustom() returns a new instance of ArrowButtonListenerCustom.
Now my Problem:
When I click on the incr/decrLabel, the List scrolls correctly, but the thumb of the ScrollBar doesn't move (or better: the Thumb isn't repainted. If I move the Mouse over the thumb, it gets repainted on the right place). I have the same problem, when I scroll with the MouseWheel.
I don't understand, why this doesn't work.
Thanks for your help!