我正在创造一个自上而下的射击游戏,让僵尸跟着你并旋转直接瞄准你。如果最多有5个僵尸,则没有闪烁。如果有超过5个僵尸,则在屏幕上绘制的所有其他图像上都会闪烁。在我看来,随着越来越多的僵尸被添加,它导致游戏运行速度变慢,并且它不时地将其他图像略微抽出。 我正在使用Graphics2D并旋转图像。然后将绘制后的图像旋转回原始位置,这样就不会影响其后绘制的其他图像。 如何以像素为单位停止闪烁和轻微移动?
提前致谢!
以下是僵尸的代码......
package com.game.stayalive;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Random;
public class Zombie extends Sprite {
Zombie() {
x = -50;
width = Display.spriteWidth;
height = Display.spriteHeight;
DELAY = rand.nextInt(8)+8;
life = 5;
}
long lastUpdate;
boolean barrierDestroyed = false;
public void drawZombie(Graphics g,int playerX, int playerY) {
if (!visible) {
return;
}
Graphics2D g2d = (Graphics2D) g;
direction = Math.atan2(y - playerY, x - playerX);
g2d.rotate(direction - Math.PI / 2.0, x + width / 2, y + height / 2);
if(DELAY > 10){
g2d.setColor(Color.green.darker());
}else{
g2d.setColor(Color.red.darker());
}
// Main body rectangle
g2d.drawRect(x, y, width, height);
// Left arm
g2d.drawRect(x - width / 2, y, width / 2, height);
g2d.fillRect(x - width / 2, y, width / 2, height);
// Right arm
g2d.drawRect(x + width, y, width / 2, height);
g2d.fillRect(x + width, y, width / 2, height);
// Main body filled
if(DELAY > 10){
g2d.setColor(Color.green);
}else{
g2d.setColor(Color.red);
}
g2d.fillRect(x, y, width, height);
g2d.rotate(-(direction - Math.PI / 2.0), x + width / 2, y + height / 2);
}
long waited = System.currentTimeMillis();
long waitTime;
public void setWaitTime(long waitTime){
this.waitTime = waitTime;
if (System.currentTimeMillis() - waited < waitTime) {
return;
}
}
int moveSpeed = 10;
public void collisionDetection(Zombie zombie1, Zombie zombie2) {
xAcc += gradientX;
yAcc += gradientY;
x = (int) xAcc;
y = (int) yAcc;
if (zombie1.getRect().intersects(zombie2.getRect()) && zombie1.visible && zombie1.life > 0) {
xAcc -= gradientX;
yAcc -= gradientY;
xAcc += (gradientX/10)+rand.nextDouble()-0.5;
yAcc += (gradientY/10) + rand.nextDouble()-0.5;
x = (int) xAcc;
y = (int) yAcc;
}
xAcc -= gradientX;
yAcc -= gradientY;
x = (int) xAcc;
y = (int) yAcc;
}
Random rand = new Random();
long spawnRate = 10000, lastZombieAdded;
public void addZombie() {
if (System.currentTimeMillis() - lastZombieAdded > spawnRate) {
Display.zombie.add(new Zombie());
Display.zombie.get(Display.zombie.size()-1).visible = true;
Display.zombie.get(Display.zombie.size()-1).setWaitTime(500);
Display.zombie.get(Display.zombie.size()-1).xAcc = rand.nextInt(950);
Display.zombie.get(Display.zombie.size()-1).yAcc = rand.nextInt(600);
lastZombieAdded = System.currentTimeMillis();
}
}
public void removeZombie(){
for (int i = 0; i < Display.zombie.size(); i++) {
if(!Display.zombie.get(i).visible ){
Display.zombie.remove(i);
}
}
}
double gradientX, gradientY;
public void move() {
setWaitTime(waitTime);
if (life <= 0) {
visible = false;
}
if (System.currentTimeMillis() - lastUpdate > DELAY) {
xAcc += gradientX;
yAcc += gradientY;
x = (int) xAcc;
y = (int) yAcc;
lastUpdate = System.currentTimeMillis();
}gradientX = -Math.cos(direction);
gradientY = -Math.sin(direction);
}
}
JPanel Class ......
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
player.drawPlayer(g2d);
for (int i = 0; i < zombie.size(); i++) {
if (zombie.get(i).visible) {
zombie.get(i).drawZombie(g2d,playerX,playerY);
}
}
for (int i = 0; i < pistol.size(); i++) {
if (pistol.get(i).visible) {
pistol.get(i).drawPistol(g2d);
}
}
for (int i = 0; i < machineGun.size(); i++) {
if (machineGun.get(i).visible) {
machineGun.get(i).drawMachineGun(g2d);
}
}
for (int i = 0; i < flamethrower.size(); i++) {
if (flamethrower.get(i).visible) {
flamethrower.get(i).draw(g2d);
}
}
reloadBar.drawReloadBar(g2d);
selector.drawSelector(g2d);
money.draw(g2d);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
@Override
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (true) {
cycle();
repaint();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;
if (sleep < 0) {
sleep = 2;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
beforeTime = System.currentTimeMillis();
}
}
}
&#34;僵尸&#34;是Zombie类的数组列表。 &#34;手枪&#34;其他也是用于子弹等的数组列表。被调用的循环方法用于移动所有图像,添加图像和检查冲突。对于代码无组织的道歉。 (我很快就会用不同的方法把它搞砸了)
答案 0 :(得分:1)
这是我放在一起的一个非常简单的例子......
它基本上有一个具有随机运动和旋转的精灵。该程序能够渲染1到10,000个僵尸......认真......
我已经使用了你&#34;主循环&#34;同样,只是为了确定......
没有真正的优化,如果我真的这样做,我会在某个地方设置一个可以拉出并放置的僵尸池,以减少创建它们所需的时间......
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ZombieLand {
protected static final Random RND = new Random();
private static BufferedImage zombie;
public static void main(String[] args) {
new ZombieLand();
}
public ZombieLand() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
zombie = ImageIO.read(getClass().getResource("/Zombie.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
final ZombiePane zombiePane = new ZombiePane();
final JSlider slider = new JSlider(1, 10000);
slider.setMajorTickSpacing(1000);
slider.setMinorTickSpacing(100);
slider.setPaintTicks(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider) e.getSource();
zombiePane.setZombies(slider.getValue());
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(zombiePane);
frame.add(slider, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
slider.setValue(10000);
}
});
}
});
}
public static class ZombiePane extends JPanel {
private List<ZombieSprite> sprites;
protected static final Object SPRITE_LOCK = new Object();
private int desiredCount = 1;
public ZombiePane() {
sprites = new ArrayList<>(25);
sprites.add(new ZombieSprite());
Thread t = new Thread(new MainLoop());
t.setDaemon(false);
t.start();
Font font = getFont();
setFont(font.deriveFont(Font.BOLD, 48f));
}
public void setZombies(int count) {
desiredCount = count;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
synchronized (SPRITE_LOCK) {
for (ZombieSprite sprite : sprites) {
sprite.paint(g2d);
}
}
String text = Integer.toString(sprites.size());
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString(text, getWidth() - fm.stringWidth(text), getHeight() - fm.getHeight() + fm.getAscent());
g2d.dispose();
}
protected void cycle() {
synchronized (SPRITE_LOCK) {
if (desiredCount != sprites.size()) {
int count = 0;
int fill = 100;
while (sprites.size() > desiredCount && count < fill) {
sprites.remove(0);
count++;
}
count = 0;
while (sprites.size() < desiredCount && count < fill) {
sprites.add(new ZombieSprite());
count++;
}
}
for (ZombieSprite sprite : sprites) {
sprite.update(getWidth(), getHeight());
}
}
}
public class MainLoop implements Runnable {
private int DELAY = 40;
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (true) {
cycle();
repaint();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;
if (sleep < 0) {
sleep = 2;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
beforeTime = System.currentTimeMillis();
}
}
}
}
public static class ZombieSprite {
// private BufferedImage zombie;
private Point motionDelta;
private double rotationDelta;
private Point location;
private double angle;
public ZombieSprite() {
motionDelta = new Point();
motionDelta.x = (int) ((Math.random() * 3) + 1);
motionDelta.y = (int) ((Math.random() * 3) + 1);
if (Math.random() > 0.5) {
motionDelta.x *= -1;
}
if (Math.random() > 0.5) {
motionDelta.y *= -1;
}
rotationDelta = (int) ((Math.random() * 9) + 1);
if (Math.random() > 0.5) {
rotationDelta *= -1;
}
}
public void paint(Graphics2D g2d) {
if (location != null) {
Graphics2D g = (Graphics2D) g2d.create();
AffineTransform at = new AffineTransform();
at.translate(location.x, location.y);
at.rotate(Math.toRadians(angle), zombie.getWidth() / 2, zombie.getHeight() / 2);
g.setTransform(at);
g.drawImage(zombie, 0, 0, null);
g.dispose();
}
}
public void update(int width, int height) {
if (location == null) {
angle = (Math.random() * 360d);
location = new Point();
location.x = (int) (Math.random() * (width - zombie.getWidth()));
location.y = (int) (Math.random() * (height - zombie.getHeight()));
} else {
angle += rotationDelta;
location.x += motionDelta.x;
location.y += motionDelta.y;
if (location.x < 0) {
location.x = 0;
motionDelta.x *= -1;
} else if (location.x + zombie.getWidth() > width) {
location.x = width - zombie.getWidth();
motionDelta.x *= -1;
}
if (location.y < 0) {
location.y = 0;
motionDelta.y *= -1;
} else if (location.y + zombie.getHeight() > height) {
location.y = height - zombie.getHeight();
motionDelta.y *= -1;
}
}
}
}
}