我想使我的应用程序绘制运动图像比当前绘制它们的方式更平滑。我不确定该怎么做。
这是我的主游戏线程的外观:
@Override
public void run(){
int delay = 500; //milliseconds
ActionListener taskPerformer = new ActionListener(){
@Override
public void actionPerformed(ActionEvent evt){
Car car = new Car();
int speed = (int)(3 + Math.floor(Math.random() * (6 - 3)));
car.setSpeed(speed);
MainLoop.this.gameObjects.vehicles.add(car.create("/Media/Graphics/blueCar.png", width - 20, 78));
car.driveTo(0, 78);
}
};
new Timer(delay, taskPerformer).start();
try{
while(true){
this.repaint();
for(GameObject go : this.gameObjects.vehicles){
// loops through objects to move them
Vehicle vh = (Vehicle) go;
this.moveVehicle(vh);
if(vh.getX() <= vh.getDestX()){
vh.markForDeletion(true);
}
}
this.gameObjects.destroyVehicles();
Thread.sleep(1);
}
}catch(Exception e){
e.printStackTrace();
}
}
这是一种计算项目下一个x / y位置的方法
protected void moveVehicle(Vehicle vh){
int cx = vh.getX();
int dx = vh.getDestX();
int cy = vh.getY();
int dy = vh.getDestY();
// move along x axis
// getMaxSpeed() = Number between 3 and 6
if(cx > dx && vh.movingX() == -1){
vh.setX(cx - vh.getMaxSpeed());
}else if(cx < dx && vh.movingX() == 1){
vh.setX(cx + vh.getMaxSpeed());
}else{
vh.setX(dx);
}
// move along y axis
// getMaxSpeed() = Number between 3 and 6
if(cy > dy && vh.movingY() == -1){
vh.setY(cy - vh.getMaxSpeed());
}else if(cy < dy && vh.movingY() == 1){
vh.setY(cy + vh.getMaxSpeed());
}else{
vh.setY(dy);
}
}
这是我的绘画方法:
@Override
public void paintComponent(Graphics graphics){
super.paintComponent(graphics);
Graphics2D g = (Graphics2D) graphics;
for(GameObject go : gameObjects.vehicles){
g.drawImage(go.getSprite(), go.getX(), go.getY(), this);
}
}
这可能比需要的信息更多,但是我想知道,我应该怎么做才能使项目从
left -> right
top -> bottom
尽可能平稳地移动,而不会造成很多性能损失?编辑:请求的sscce:
package sscce;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Sscce extends JPanel implements Runnable{
ArrayList<Square> squares = new ArrayList<>();
public Sscce(){
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(this);
Thread t = new Thread(this);
t.start();
}
public static void main(String[] args){
new Sscce();
}
@Override
public void run(){
int delay = 500; //milliseconds
ActionListener taskPerformer = new ActionListener(){
@Override
public void actionPerformed(ActionEvent evt){
Square squ = new Square();
Sscce.this.squares.add(squ);
squ.moveTo(0);
}
};
new Timer(delay, taskPerformer).start();
while(true){
try{
for(Square s : this.squares){
int objX = s.getX();
int desX = s.getDestX();
if(objX <= desX){
System.out.println("removing");
this.squares.remove(s);
}else{
s.setX(s.getX() - 10);
}
}
this.repaint();
Thread.sleep(30);
}catch(Exception e){
}
}
}
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for(Square s : squares){
g.setColor(Color.blue);
g.fillRect(s.getX(), s.getY(), 50, 50);
}
}
}
class Square{
public int x = 0, y = 0, destX = 0;
public Square(){
this.x = 400;
this.y = 100;
}
public void moveTo(int destX){
this.destX = destX;
}
public int getX(){
return this.x;
}
public int getDestX(){
return this.destX;
}
public void setX(int x){
this.x = x;
}
public int getY(){
return this.y;
}
}
最佳答案
首先要注意的是,由于某些原因,在MacOS下运行JPanel
时,我遇到了Runnable
的问题-我不知道为什么,但这就是为什么将其移出了原因。squares
可能会在用于绘制时进行更新,这会导致异常(另外,在迭代时从列表中删除元素也不是一个好主意;))
相反,我有两个列表。我有一个模型,列表可以修改,然后paint
方法可以使用的绘画列表。这允许线程在绘制过程中修改模型。
为了防止发生任何冲突,我添加了一个锁,该锁可以防止一个线程修改/访问绘画列表,而另一个线程将其锁定。
现在。归结到真正的问题。您遇到的主要问题不是两次更新之间的时间长短,而是您移动的距离。缩短距离(使其变慢)并使更新标准化。
大多数人不会注意到超过25fps的速度,因此尝试做更多的事情就是浪费CPU周期,使重新绘制管理器饿死,从而阻止它实际更新屏幕。
确保这是平衡的举动...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestAnimation11 extends JPanel {
private ArrayList<Square> squares = new ArrayList<>();
private ReentrantLock lock;
public TestAnimation11() {
lock = new ReentrantLock();
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(TestAnimation11.this);
Thread t = new Thread(new UpdateEngine());
t.start();
}
});
}
public static void main(String[] args) {
new TestAnimation11();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Square[] paint = null;
lock.lock();
try {
paint = squares.toArray(new Square[squares.size()]);
} finally {
lock.unlock();
}
for (Square s : paint) {
g.setColor(Color.blue);
g.fillRect(s.getX(), s.getY(), 50, 50);
}
}
public class UpdateEngine implements Runnable {
private List<Square> model = new ArrayList<>(squares);
@Override
public void run() {
int ticks = 0;
List<Square> dispose = new ArrayList<>(25);
while (true) {
ticks++;
dispose.clear();
for (Square s : model) {
int objX = s.getX();
int desX = s.getDestX();
if (objX <= desX) {
dispose.add(s);
} else {
s.setX(s.getX() - 2);
}
}
model.removeAll(dispose);
if (ticks == 11) {
Square sqr = new Square();
sqr.moveTo(0);
model.add(sqr);
} else if (ticks >= 25) {
ticks = 0;
}
lock.lock();
try {
squares.clear();
squares.addAll(model);
} finally {
lock.unlock();
}
repaint();
try {
Thread.sleep(40);
} catch (Exception e) {
}
}
}
}
class Square {
public int x = 0, y = 0, destX = 0;
public Square() {
this.x = 400;
this.y = 100;
}
public void moveTo(int destX) {
this.destX = destX;
}
public int getX() {
return this.x;
}
public int getDestX() {
return this.destX;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return this.y;
}
}
}
关于java - 平滑Java绘画动画,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15329117/