快速移动时的JavaFX图像重影
我偶然发现了一个问题:如果图像在屏幕上高速移动,它会被错误地渲染,从而产生重影效果。我想我们可以排除我的显示器的问题,因为这种类型的运动是完美的摇摆(以相同的帧率) 看起来像: 代码(从3个类中合并):快速移动时的JavaFX图像重影,java,image,swing,javafx-8,Java,Image,Swing,Javafx 8,我偶然发现了一个问题:如果图像在屏幕上高速移动,它会被错误地渲染,从而产生重影效果。我想我们可以排除我的显示器的问题,因为这种类型的运动是完美的摇摆(以相同的帧率) 看起来像: 代码(从3个类中合并): 导入javafx.animation.AnimationTimer; 导入javafx.application.application; 导入javafx.event.EventHandler; 导入javafx.scene.Group; 导入javafx.scene.scene; 导入java
导入javafx.animation.AnimationTimer;
导入javafx.application.application;
导入javafx.event.EventHandler;
导入javafx.scene.Group;
导入javafx.scene.scene;
导入javafx.scene.image.image;
导入javafx.scene.image.ImageView;
导入javafx.scene.input.KeyCode;
导入javafx.scene.input.KeyEvent;
导入javafx.scene.paint.Color;
导入javafx.stage.stage;
导入javafx.stage.StageStyle;
导入java.awt.Dimension;
导入java.awt.Toolkit;
公共类构造函数扩展应用程序{
图像播放器,镜头;
静态维度屏幕=新维度(Toolkit.getDefaultToolkit().getScreenSize());
静态int wid=屏幕宽度;
静态int hei=屏幕高度;
静态布尔向上、向下、左、右、左、右;
静态双x=(wid/2)-109;
静态双y=(hei/1.5)-132;
静态双velx=0,Fly=0,velx2=0,vely2=0;
静态双前速度=0,侧速度=0;
静态整数旋转=0;
公共空荷载(){
player=新图像(“res/sprite.png”);
}
@凌驾
public void start(最终阶段帧)引发异常{
加载();
frame.setTitle(“默认”);
框架。初始样式(舞台样式。未装饰);
组根=新组();
最终ImageView发货=新ImageView();
ship.setImage(播放器);
root.getChildren().add(ship);
frame.setScene(新场景(root、wid、hei、Color.BLACK));
frame.addEventHandler(按下KeyEvent.KEY_,新建EventHandler()){
公共无效句柄(KeyEvent密钥){
if(key.getCode()==KeyCode.W)
向上=真;
if(key.getCode()==KeyCode.S)
向下=真;
if(key.getCode()==KeyCode.Q)
左=真;
if(key.getCode()==KeyCode.E)
右=真;
if(key.getCode()==KeyCode.A)
左=真;
if(key.getCode()==KeyCode.D)
右=真;
}
});
frame.addEventHandler(KeyEvent.KEY_已发布,新的EventHandler(){
公共无效句柄(KeyEvent密钥){
if(key.getCode()==KeyCode.ESCAPE)
{
frame.close();
系统出口(0);
}
if(key.getCode()==KeyCode.W)
向上=错误;
if(key.getCode()==KeyCode.S)
向下=假;
if(key.getCode()==KeyCode.Q)
左=假;
if(key.getCode()==KeyCode.E)
右=假;
if(key.getCode()==KeyCode.A)
左=假;
if(key.getCode()==KeyCode.D)
右=假;
}
});
frame.setAlwaysOnTop(真);
帧设置高度(hei);
帧设置宽度(wid);
frame.setresizeable(false);
frame.setFullScreen(真);
frame.show();
新的AnimationTimer(){
@凌驾
公共无效句柄(长){
gameloop();
ship.setTranslateX(x);
船舶。setTranslateY(y);
ship.setRotate(旋转);
}
}.start();
}
公共静态void gameloop(){
if(Shared.up)
速度+=1;
if(Shared.down)
速度-=1;
if(Shared.right)
侧速度+=1;
if(Shared.left)
侧速度-=1;
if(Shared.rotlight)
旋转-=3;
if(Shared.rotright)
rotat+=3;
velx=数学常数cos(数学常数toRadians(rotat-90))*速度+数学常数cos(数学常数toRadians(rotat))*侧速度;
vely=Math.sin(Math.toRadians(rotat-90))*速度+Math.sin(Math.toRadians(rotat))*侧速度;
如果(!Shared.up&&!Shared.down)
{
如果(速度>0时)
速度-=0.2;
否则如果(速度<0时)
速度+=0.2;
}
如果(!Shared.right&&!Shared.left)
{
如果(侧速度>0)
侧速度-=0.2;
否则,如果(侧速度<0)
侧速度+=0.2;
}
x+=velx;
y+=0;
筛检结肠炎();
}
私有静态无效屏幕合并(){
//左右
if(x<0)
{
x=0;
侧速度=0;
}
else if(x+218>Shared.wid)
{
x=共享的wid-218;
侧速度=0;
}
//上下
if(y<0)
{
y=0;
forspeed=0;
}
否则如果(y+164>共享.hei)
{
y=共享。hei-164;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import java.awt.Dimension;
import java.awt.Toolkit;
public class Constructor extends Application{
Image player, shot;
static Dimension screen = new Dimension(Toolkit.getDefaultToolkit().getScreenSize());
static int wid = screen.width;
static int hei = screen.height;
static boolean up, down, left, right, rotleft , rotright;
static double x = (wid/2)-109;
static double y = (hei/1.5)-132;
static double velx = 0, vely = 0, velx2 = 0, vely2 = 0;
static double forspeed = 0, sidespeed = 0;
static int rotat = 0;
public void load(){
player = new Image("res/sprite.png");
}
@Override
public void start(final Stage frame) throws Exception{
load();
frame.setTitle("DEFAULT");
frame.initStyle(StageStyle.UNDECORATED);
Group root = new Group();
final ImageView ship = new ImageView();
ship.setImage(player);
root.getChildren().add(ship);
frame.setScene(new Scene(root, wid, hei, Color.BLACK));
frame.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>(){
public void handle(KeyEvent key) {
if(key.getCode()==KeyCode.W)
up = true;
if(key.getCode()==KeyCode.S)
down = true;
if(key.getCode()==KeyCode.Q)
left = true;
if(key.getCode()==KeyCode.E)
right = true;
if(key.getCode()==KeyCode.A)
rotleft = true;
if(key.getCode()==KeyCode.D)
rotright = true;
}
});
frame.addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>(){
public void handle(KeyEvent key) {
if(key.getCode()==KeyCode.ESCAPE)
{
frame.close();
System.exit(0);
}
if(key.getCode()==KeyCode.W)
up = false;
if(key.getCode()==KeyCode.S)
down = false;
if(key.getCode()==KeyCode.Q)
left = false;
if(key.getCode()==KeyCode.E)
right = false;
if(key.getCode()==KeyCode.A)
rotleft = false;
if(key.getCode()==KeyCode.D)
rotright = false;
}
});
frame.setAlwaysOnTop(true);
frame.setHeight(hei);
frame.setWidth(wid);
frame.setResizable(false);
frame.setFullScreen(true);
frame.show();
new AnimationTimer() {
@Override
public void handle(long now) {
gameloop();
ship.setTranslateX(x);
ship.setTranslateY(y);
ship.setRotate(rotat);
}
}.start();
}
public static void gameloop(){
if(Shared.up)
forspeed += 1;
if(Shared.down)
forspeed -= 1;
if(Shared.right)
sidespeed += 1;
if(Shared.left)
sidespeed -= 1;
if(Shared.rotleft)
rotat -=3;
if(Shared.rotright)
rotat +=3;
velx = Math.cos(Math.toRadians(rotat-90))*forspeed + Math.cos(Math.toRadians(rotat))*sidespeed;
vely = Math.sin(Math.toRadians(rotat-90))*forspeed + Math.sin(Math.toRadians(rotat))*sidespeed;
if(!Shared.up && !Shared.down)
{
if(forspeed > 0)
forspeed -= 0.2;
else if (forspeed < 0)
forspeed += 0.2;
}
if(!Shared.right && !Shared.left)
{
if(sidespeed > 0)
sidespeed -= 0.2;
else if (sidespeed < 0)
sidespeed += 0.2;
}
x += velx;
y += vely;
screencolisions();
}
private static void screencolisions() {
// LEFT RIGHT
if(x < 0)
{
x = 0;
sidespeed = 0;
}
else if (x+218 > Shared.wid)
{
x = Shared.wid-218;
sidespeed = 0;
}
// UP DOWN
if(y < 0)
{
y = 0;
forspeed = 0;
}
else if (y+164 > Shared.hei)
{
y = Shared.hei-164;
forspeed = 0;
}
}
public static void main(String[] args){
Application.launch(args);
}
}
Screen screen = Screen.getPrimary();
wid = screen.getBounds().getWidth();
hei = screen.getBounds().getHeight();
// Visual bounds will be different depending on OS and native toolbars etc..
// think of it as desktop bounds vs whole screen
public class ScreenBounds extends Application {
@Override
public void start(Stage primaryStage) {
Screen screen = Screen.getPrimary();
System.out.println("ScreenBounds : " + screen.getBounds() + "\nVisualBounds : " + screen.getVisualBounds());
Platform.exit();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
compile-single:
run-single:
ScreenBounds : Rectangle2D [minX = 0.0, minY=0.0, maxX=1680.0, maxY=1050.0, width=1680.0, height=1050.0]
VisualBounds : Rectangle2D [minX = 0.0, minY=40.0, maxX=1680.0, maxY=1050.0, width=1680.0, height=1010.0]
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.util.Duration;
/**
*
* @author jdub1581
*/
public class NanoTimer extends ScheduledService<Void> {
private final long ONE_NANO = 1000000000L;
private final double ONE_NANO_INV = 1f / 1000000000L;
private long startTime, previousTime;
private double frameRate, deltaTime;
private final NanoThreadFactory tf = new NanoThreadFactory();
public NanoTimer() {
super();
this.setPeriod(Duration.millis(16));// equivalent to 60 fps
this.setExecutor(Executors.newCachedThreadPool(tf));
}
public double getTimeAsSeconds() {
return getTime() * ONE_NANO_INV;
}
public long getTime() {
return System.nanoTime() - startTime;
}
public long getOneSecondAsNano() {
return ONE_NANO;
}
public double getFrameRate() {
return frameRate;
}
public double getDeltaTime() {
return deltaTime;
}
private void updateTimer() {
deltaTime = (getTime() - previousTime) * (1.0f / ONE_NANO);
frameRate = 1.0f / deltaTime;
previousTime = getTime();
}
@Override
public void start() {
super.start();
if (startTime <= 0) {
startTime = System.nanoTime();
}
}
@Override
public void reset() {
super.reset();
startTime = System.nanoTime();
previousTime = getTime();
}
private boolean init = true;
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
updateTimer();
// perform NON UI calculations here
return null;
}
};
}
@Override
protected void succeeded() {
super.succeeded();
//update the UI here
}
@Override
protected void failed() {
getException().printStackTrace(System.err);
}
@Override
public String toString() {
return "ElapsedTime: " + getTime() + "\nTime in seconds: " + getTimeAsSeconds()
+ "\nFrame Rate: " + getFrameRate()
+ "\nDeltaTime: " + getDeltaTime();
}
/*==========================================================================
creates a daemon thread for use
*/
private class NanoThreadFactory implements ThreadFactory {
public NanoThreadFactory() {
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "NanoTimerThread");
t.setDaemon(true);
return t;
}
}
}//=============================================================================