Java - pressing a direction key and having it move smoothly - keylistener

When I press a direction key to move the object in that direction, it moves once, pauses momentarily, then moves again. Kind of like how if I want to type "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", I would hold "a" key down, but after the first "a" there is a pause then the rest of the "a"'s are typed. How do I remove that pause in KeyListener? Thank you.

This is the key repetition feature that the OS provides, so there is no way around the pauses.
The way most games gets around this is to keep an array of the current state of all required keys and check periodically on them (for example in the game loop) and act on that (e.g move).
public class KTest extends JFrame implements KeyListener {
private boolean[] keyState = new boolean[256];
public static void main(String[] args) {
new KeyTest();
int xVelocity = 0;
int x = 0;
while(1) {
xVelocity = 0;
if(keyState[KeyEvent.VK_LEFT]) {
xVelocity = -5;
}
x += xVelocity;
}
}
KTest() {
this.addKeyListener(this);
}
void keyPressed(KeyEvent e) {
key_state[e.getKeyCode()] = true;
}
void keyReleased(KeyEvent e) {
key_state[e.getKeyCode()] = false;
}
}
Base class taken from: http://content.gpwiki.org/index.php/Java:Tutorials:Key_States

Related

Trying to make Unending Boundaries In a Runner Game

Trying to make a runner game. I don't want my character to fall off the edge of the map. How do I make the character always center of the path? I want to make so that my character is always center of the path as it is being instantiated and to never fall off the map.
public class GroundTile : MonoBehaviour
{
GroundSpawner groundSpawner;
// Start is called before the first frame update
private void Start()
{
groundSpawner = GameObject.FindObjectOfType<GroundSpawner>();
}
private void OnTriggerExit (Collider other)
{
groundSpawner.SpawnTile();
Destroy(gameObject, 2);
}
// Update is called once per frame
void Update()
{
}
}
public class GroundSpawner : MonoBehaviour
{
public GameObject groundTile;
Vector3 nextSpawnPoint;
// Start is called before the first frame update
public void SpawnTile()
{
GameObject temp = Instantiate(groundTile, nextSpawnPoint, Quaternion.identity);
nextSpawnPoint = temp.transform.GetChild(1).transform.position;
}
private void Start()
{
for (int i = 0; i < 10; i++)
{
SpawnTile();
}
}
}
I tried so many methods.

How to implement undo function without violating encapsulation?

Lets image a simple board game:
Every turn you can place one figure.
You must not remove a figure.
When a certain condition is met, the game is over.
Now I want to implement an undo function.
I have to following classes:
Game {
(...)
+ placeFigure(int,int): void
+ isGameOver(): bool
}
Move {
(...)
+ Move(Game,int,int)
+ execute(): void
+ undo(): void
}
History {
- moves: List<Move>
(...)
+ add(Move): void
+ undo(): void
}
My problem is, in order for a move to be undone, I have to add a function removeFigure.
But, calling this function improperly would result in an invalid state.
The other idea I hade was to make Move a nested class of Game.
This however, will bloat the Game class and make it tedious to add other possible moves in the future.
Should I implement one of those ideas?
Perhaps there is a simpler solution to this problem?
Without knowing the exact objectives of your game nor what other types of moves you had in mind (I assumed moves that also place figures), here's the approach I, in java, would probably take based on the current constraints you've put forth.
/* Game.java */
import java.util.Stack;
public class Game
{
protected static abstract class Move
{
protected final int x;
protected final int y;
protected Move(int x, int y) {
this.x = x;
this.y = y;
}
protected void execute(Game game) {
game.placeFigure(x, y);
}
protected void undo(Game game) {
game.removeFigure(x, y);
}
}
private Stack<Move> history = new Stack<Move>();
public void doMove(Move move) {
move.execute(this);
history.push(move);
}
public void undoMove() {
if(history.empty()) {
System.out.println("no move to undo");
}
else {
Move move = history.pop();
move.undo(this);
}
}
protected void placeFigure(int x, int y) {
System.out.println("place figure at: " + x + "," + y);
}
protected void removeFigure(int x, int y) {
System.out.println("remove figure at: " + x + "," + y);
}
}
/* DefaultMove.java */
public class DefaultMove extends Game.Move
{
public DefaultMove(int x, int y) {
super(x, y);
}
}
/* SpecialMove.java */
public class SpecialMove extends Game.Move
{
public SpecialMove(int x, int y) {
super(x + 10, y + 10);
System.out.println("SpecialMove displaces x and y by 10");
}
}
/* Main.java */
public class Main
{
public static void main(String[] arguments) {
Game game = new Game();
DefaultMove defaultMove = new DefaultMove(3,6);
SpecialMove specialMove = new SpecialMove(4,5);
game.doMove(defaultMove);
game.doMove(specialMove);
game.undoMove();
game.undoMove();
game.undoMove();
}
}
Which prints:
SpecialMove displaces x and y by 10
place figure at: 3,6
place figure at: 14,15
remove figure at: 14,15
remove figure at: 3,6
no move to undo
Maybe it's not at all what you are looking for, but hopefully this gives you some ideas to work with. Let me know if you had completely other objectives in mind and I'll see if I can accommodate.

Unable to identify where a NullPointerException is coming from

so I am getting the following error:
Exception in thread "Thread-0" java.lang.NullPointerException
at dev.tamir.firstgame.entities.creatures.Player.getInput(Player.java:19)
at dev.tamir.firstgame.entities.creatures.Player.tick(Player.java:31)
at dev.tamir.firstgame.states.GameState.tick(GameState.java:25)
at dev.tamir.firstgame.Game.tick(Game.java:65)
at dev.tamir.firstgame.Game.run(Game.java:110)
at java.lang.Thread.run(Unknown Source)
And I've checked all the lines Java had marked me and I can not find what is producing the null.
Player:
package dev.tamir.firstgame.entities.creatures;
import java.awt.Graphics;
import dev.tamir.firstgame.Game;
import dev.tamir.firstgame.gfx.Assets;
public class Player extends Creature {
private Game game;
public Player(Game game, float x, float y) {
super(game, x, y, Creature.DEFAULT_CREATURE_WIDTH, Creature.DEFAULT_CREATURE_HEIGHT);
}
#Override
public void tick() {
getInput();
move();
game.getGameCamera().centerOnEntity(this);
}
private void getInput() {
xMove = 0;
yMove = 0;
if(game.getKeyManager().up)
yMove = -speed;
if(game.getKeyManager().down)
yMove = speed;
if(game.getKeyManager().left)
xMove = -speed;
if(game.getKeyManager().right)
xMove = speed;
}
#Override
public void render(Graphics g) {
g.drawImage(Assets.robro[7], (int) (x - game.getGameCamera().getxOffset()), (int) (y - game.getGameCamera().getyOffset()), width, height, null);
}
}
Gamestate:
package dev.tamir.firstgame.states;
import java.awt.Graphics;
import dev.tamir.firstgame.Game;
import dev.tamir.firstgame.entities.creatures.Player;
import dev.tamir.firstgame.tiles.Tile;
import dev.tamir.firstgame.worlds.World;
public class GameState extends State {
private Player player;
private World world;
public GameState(Game game) {
super(game);
player = new Player(game, 0, 0);
world = new World(game, "res/worlds/world1.txt");
}
#Override
public void tick() {
world.tick();
player.tick();
}
#Override
public void render(Graphics g) {
world.render(g);
player.render(g);
}
}
Game:
package dev.tamir.firstgame;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import dev.tamir.firstgame.Display.Display;
import dev.tamir.firstgame.gfx.Assets;
import dev.tamir.firstgame.gfx.GameCamera;
import dev.tamir.firstgame.input.KeyManager;
import dev.tamir.firstgame.states.GameState;
import dev.tamir.firstgame.states.MenuState;
import dev.tamir.firstgame.states.State;
public class Game implements Runnable {
private Display display;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
//States
private State gameState;
private State menuState;
//Input
private KeyManager keyManager;
//Camera
private GameCamera gameCamera;
private boolean running = false;
private int width, height;
public String title;
public Game(String title, int width, int height) {
this.width = width;
this.height = height;
this.title = title;
keyManager = new KeyManager();
}
private void init() {
display = new Display(title, width, height);
display.getFrame().addKeyListener(keyManager);
Assets.init();
gameCamera = new GameCamera(this, 0,0);
gameState = new GameState(this);
menuState = new MenuState(this);
State.setState(gameState);
}
private void tick() {
keyManager.tick();
if(State.getState() != null)
State.getState().tick();
}
private void render() {
bs = display.getCanvas().getBufferStrategy();
if(bs == null) {
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Clear
g.clearRect(0, 0, width, height);
//Draw
if(State.getState() != null)
State.getState().render(g);
//End of Draw
bs.show();
g.dispose();
}
public void run() {
init();
int fps = 60;
double timePerTick = 1000000000 / fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
long timer = 0;
int ticks = 0;
while (running) {
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
timer += now - lastTime;
lastTime = now;
if(delta >= 1) {
tick();
render();
ticks++;
delta--;
}
if(timer >= 1000000000) {
System.out.println("FPS: " + ticks );
ticks = 0;
timer = 0;
}
}
stop();
}
public KeyManager getKeyManager() {
return keyManager;
}
public GameCamera getGameCamera() {
return gameCamera;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public synchronized void start() {
if (running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
if (!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
help would be very appreciated, as I've been looking for hours now and I don't know what is causing the null and I am suspecting the error log may even be misleading me.
My guess would be you have a private Game in your creature class. When you call super() in Player, you pass a Game object to Creature. The Creature constructor most likely has a line like this.game = game;
Of course, I can't say for sure because the Creature class is not included in your post, but that's the most likely code setup. Because game would then be private to Creature, Player cannot see it. That means the private Game game that you declare in Player is never set.
After you call super, do this.game = game;
This will almost certainly take care of your issue.
Just for future reference, the message you got when the error resulted is the call stack; basically it tells you what methods called what, the most recent being at the top. The error took place at line 19 in Player.getInput(), which was called by tick() in that same class.
The only object you use in getInput() is game, and so that must be the source of the null pointer. From there, it's a quick check to see that game is a private field of Player, and since it is null that's a huge clue that it was never initialized (though that is not always the case). Private fields most often are initialized in the class constuctor (but they don't have to be... your Player class is pretty sparse so it wouldn't take that long to look through all of it if you absolutly had to. Looking at the Player constructor, we see a Game object named game is passed in, which suggests that it was intended to be used to initialize game and yet never is. VoilĂ , we found the problem!
I'm sorry if that last paragraph felt a little condecending; it wasn't meant to be. I just wanted to walk you through how I found your issue. Hopefully knowing how I found it will help you find later errors on your own.

How do I implement a mouse event outside the Java frame?

I am trying to make a return program which will press the enter key when the left mouse key is clicked...
with courtesy of
http://www.java-tips.org/java-se-tips/java.awt/how-to-use-robot-class-in-java.html (for void typing method) and "thenewboston" I have gotten so far...
I am trying to make it so that it will function in other platforms, for example: Word, Note Pad and not just on a JFrame
This is what I have up till now...
import java.awt.event.MouseEvent;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Robot;
import java.awt.event.KeyEvent;
public class MW3Tool
{
public static void main (String[] args)
{
Robot enter = new Robot();
int num;
return count = 0;
num = count * 3;
Control c = new Control();
for (int k = 1; k <= num; k++)
{System.out.println("H");}
/* try {
Robot robot = new Robot(); // Going to be used to electronically hit the enter key later.
robot.delay(5000);
robot.setSpeed(10);
for (int k = 1; k<= num; k ++)
robot.keyPress(KeyEvent.VK_ENTER);
}
catch (AWTException e) {
e.printStackTrace();
} } */
}
private class Control implements MouseListener
{
int count;
int useless;
int useless2;
public void mouseClicked(MouseEvent event)
{
count++;
}
public void mousePressed(MouseEvent event)
{
useless++;
}
public void mouseExited(MouseEvent event)
{
useless2++;
}
}
}
My errors:
----jGRASP exec: javac -g MW3Tool.java
MW3Tool.java:20: cannot return a value from method whose result type is void
return count = 0;
^
MW3Tool.java:22: cannot find symbol
symbol : variable count
location: class MW3Tool
num = count * 3;
^
MW3Tool.java:35: non-static variable this cannot be referenced from a static context
Control c = new Control();
^
MW3Tool.java:60: MW3Tool.Control is not abstract and does not override abstract method mouseEntered(java.awt.event.MouseEvent) in java.awt.event.MouseListener
private class Control implements MouseListener
^
4 errors
----jGRASP wedge2: exit code for process is 1.
----jGRASP: operation complete.
Sorry for my inefficient methods (newly affiliated with Java)
Any help will be appreciated... thank you...
First error: Are you trying to initialize an Integer? Wrong syntax. Use
int count = 0;
Second error: Solving the first error will solve this error.
Third error: Instead of saying
private class Control implements MouseListener { ... }
Say
private static class Control implements MouseListener { ... }
Last error:
See the MouseListener Javadocs:
Method Summary
void mouseClicked(MouseEvent e)
Invoked when the mouse button has been clicked (pressed and released) on a component.
void mouseEntered(MouseEvent e)
Invoked when the mouse enters a component.
void mouseExited(MouseEvent e)
Invoked when the mouse exits a component.
void mousePressed(MouseEvent e)
Invoked when a mouse button has been pressed on a component.
void mouseReleased(MouseEvent e)
Invoked when a mouse button has been released on a component.
You MUST override all of these methods in the Control class for your program to work.
Hope this helps!

How can I detect when the XAML Slider is Completed?

In XAML I have the <Slider />. It has the ValueChanged event. This event fires with every change to Value. I need to detect when the value change is over. LostFocus, PointerReleased are not the correct event. How can I detect this?
XAML, WinRT, Windows8.1 and UWP:
PointerCaptureLost event should work for mouse / touch
KeyUp event for keyboard
You can create a new class and inherit from Slider. From there on, you can look for the Thumb control & listen for the events you want.
Something like this should work:
public class SliderValueChangeCompletedEventArgs : RoutedEventArgs
{
private readonly double _value;
public double Value { get { return _value; } }
public SliderValueChangeCompletedEventArgs(double value)
{
_value = value;
}
}
public delegate void SlideValueChangeCompletedEventHandler(object sender, SliderValueChangeCompletedEventArgs args);
public class ExtendedSlider : Slider
{
public event SlideValueChangeCompletedEventHandler ValueChangeCompleted;
private bool _dragging = false;
protected void OnValueChangeCompleted(double value)
{
if (ValueChangeCompleted != null)
{
ValueChangeCompleted(this, new SliderValueChangeCompletedEventArgs(value) );
}
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var thumb = base.GetTemplateChild("HorizontalThumb") as Thumb;
if (thumb != null)
{
thumb.DragStarted += ThumbOnDragStarted;
thumb.DragCompleted += ThumbOnDragCompleted;
}
thumb = base.GetTemplateChild("VerticalThumb") as Thumb;
if (thumb != null)
{
thumb.DragStarted += ThumbOnDragStarted;
thumb.DragCompleted += ThumbOnDragCompleted;
}
}
private void ThumbOnDragCompleted(object sender, DragCompletedEventArgs e)
{
_dragging = false;
OnValueChangeCompleted(this.Value);
}
private void ThumbOnDragStarted(object sender, DragStartedEventArgs e)
{
_dragging = true;
}
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
if (!_dragging)
{
OnValueChangeCompleted(newValue);
}
}
}
You can use pair of bool values isValueChanged and (if possible change value without manipulation of pointer
) isPressed;
private void Slider_ValueChanged(object s, RangeBaseValueChangedEventArgs e) {
if (!isPressed) {
AcceptChanges();
} else {
isValueChanged = true;
}
}
Initialization code:
Window.Current.CoreWindow.PointerPressed += (e, a) => { isPressed = true; };
Window.Current.CoreWindow.PointerReleased += (e, a) => {
isPressed = false;
if (isValueChanged) AcceptChanges();
};
I had a similar issue using a Slider on Windows8/WinRT.
My problem was the following: I was reacting to the ValueChanged Event and performing a long lasting operation (writing asynchronously to a file) after each trigger. And thus running into a concurrent editing exception. In order to avoid this, I used a DispatcherTimer.
//Class member
private DispatcherTimer myDispatcherTimer = null;
private void OnSliderValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
//I update my UI right away
...
//If the dispatcher is already created, stop it
if (myDispatcherTimer!= null)
myDispatcherTimer.Stop();
//Overwrite the DispatcherTimer and thus reset the countdown
myDispatcherTimer= new DispatcherTimer();
myDispatcherTimer.Tick += (sender, o) => DoSomethingAsync();
myDispatcherTimer.Interval = new TimeSpan(0,0,2);
myDispatcherTimer.Start();
}
private async void DoSomethingAsync()
{
await DoThatLongSaveOperation();
}
You cannot directly detect what the final value is, but you can at least delay the operation until there is a long pause between two updates (e.g. in my case, if the user drags the slider and stops while maintaining the drag for 2 seconds, the save operation will be fired anyway).