如何在java中缓慢移动子弹?
嗨,我正在开发一个游戏,一个战士左右移动并射击。对于射击部分,我尝试使用For循环来降低速度,用户可以看到子弹。但这还不够。我也用睡眠,但不是一个好答案。现在我不知道该怎么办。 这是我的油漆组件:如何在java中缓慢移动子弹?,java,move,Java,Move,嗨,我正在开发一个游戏,一个战士左右移动并射击。对于射击部分,我尝试使用For循环来降低速度,用户可以看到子弹。但这还不够。我也用睡眠,但不是一个好答案。现在我不知道该怎么办。 这是我的油漆组件: package game; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.KeyEvent; import java.awt.event.KeyLi
package game;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class PaintComponent extends JPanel implements KeyListener {
int dx = 200-15;
int dy = 450;
int my = 450;
ArrayList<Bullet> bullets = new ArrayList<>();
public Rectangle2D rec =new Rectangle2D.Double(dx , dy, 30, 10);
Rectangle2D recB = new Rectangle2D.Double(dx+13 , my, 6, 6);
// public Polygon pol = new Polygon
private BufferedImage imageBg, imageFi, imageBu;
public PaintComponent() {
this.addKeyListener(this);
this.setFocusable(true);
this.setBackground(Color.white);
try {
imageBg = ImageIO.read(new File("C:\\Java\\NetbeansProjects\\Game\\bg.jpg"));
imageBu = ImageIO.read(new File("C:\\Java\\NetbeansProjects\\Game\\bul.png"));
imageFi = ImageIO.read(new File("C:\\Java\\NetbeansProjects\\Game\\fi.png"));
} catch (IOException ex) {
System.out.println("No background image is available!");
}
}
public void shoot(){
if(bullets != null){
for(int i=0; i<bullets.size(); i++){
for(int j=0; j<200; j++){
bullets.get(i).setdy(my-j);
}
System.out.println(bullets.get(i).getdy());
}
}
}
public void moveRec(KeyEvent evt){
switch(evt.getKeyCode()){
case KeyEvent.VK_LEFT:
dx -= 5;
rec.setRect(dx, dy, 30, 10);
recB.setRect(dx+13, dy, 6, 6);
repaint();
break;
case KeyEvent.VK_RIGHT:
dx += 5;
rec.setRect(dx, dy, 30, 10);
recB.setRect(dx+13, dy, 6, 6);
repaint();
break;
case KeyEvent.VK_SPACE:
Bullet b = new Bullet(dx, dy);
bullets.add(b);
shoot();
break;
}
}
@Override
public void paintComponent(Graphics grphcs)
{super.paintComponent(grphcs);
Graphics2D gr = (Graphics2D) grphcs;
int X = (int) rec.getCenterX();
int Y = (int) rec.getCenterY();
gr.drawImage(imageBg, 0, 0, null);
gr.drawImage(imageFi, X-50, Y-75, null);
gr.setColor(Color.GRAY);
if(bullets != null){
for(int i=0;i<bullets.size();i++){
gr.drawImage(imageBu, null, bullets.get(i).getdx(), bullets.get(i).getdy());
repaint();
}
}
gr.draw(recB);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e)
{moveRec(e);}
@Override
public void keyReleased(KeyEvent e)
{}
}
在你的游戏循环中,让它每隔这么多次更新子弹。你很可能永远都不想用睡眠来减缓游戏中的某些事情,因为它需要一个新的线程,否则它会使整个游戏处于睡眠状态 如果你不知道什么是游戏循环,游戏循环基本上是一个循环,它不断地接受输入,更新游戏,如子弹,渲染所有内容,然后暂停整个程序,你可以使用睡眠来维持循环所剩余的预期时间。您还需要根据上次更新后经过的滴答声或毫秒数来更新游戏。这将防止游戏在不同的计算机上运行得更快或更慢 我还没读完这本书,但可能会有所帮助 另外,我不确定这是否正确,我认为使用Canvas而不是JPanel会更好地制作游戏。这是我在第一个java游戏中使用的 编辑: 如果您想使用JPanel而不使用游戏循环,您可以让shot方法创建一个新线程,并使用sleep来减慢它的速度。此外,如果发射多个项目符号,则使用“发射方法”设置的方式可能会导致问题,因为它将在两个单独的循环中循环通过每个项目符号;如果使用单独的线程,则可以在一个线程中循环时修改项目符号数组,从而导致错误 试试这个:
public void shoot(Bullet bullet){
new Thread(new Runnable(){
for(int j=0; j<200; j++){
bullet.setdy(my-j);
try{
Thread.sleep(time);//set the time
catch(Exception e){
e.printStackTrace();
}
}
System.out.println(bullet.getdy());
getBullets().remove(bullet);
}).start();
}
创建一个名为getBullets的方法。确保它具有同步修改器
protected synchronized ArrayList<Bullet> getBullets(){
return bullets;
}
这将确保一次只能由一个线程修改它
最后,在玩家按下空格键的地方,更改bullets.addb;获取bullets.addb 我认为你放慢循环的速度是错误的。你最不想做的事情就是放慢游戏循环的速度或者让游戏循环休眠。这将影响游戏中的所有对象 有多种方法可以做到这一点: 每刻度的较小增量 你能做的最明显的一件事就是减小子弹的增量。让我们看看你的拍摄;方法:
public void shoot(){
if(bullets != null){
for(int i=0; i<bullets.size(); i++){
for(int j=0; j<200; j++){
bullets.get(i).setdy(my-j);
}
System.out.println(bullets.get(i).getdy());
}
}
}
代码现在所做的是,它根据生存时间变量计算速度,子弹的生存时间越长,速度就越小。调整速度变量可以更好地控制子弹。我自己也这么说,拍摄方法看起来更整洁:
public void shoot(){
if(bullets != null){
for(int i=0; i<bullets.size(); i++){
bullets.get(i).Move();
}
}
}
当然还有很多,比如检查生活的速度和时间是否超出界限之类的,但我认为你足够聪明,能够弄清楚这一点
用定时器运行它
正如ControlAltDel所说,你可以实现一个定时器,我不是java方面的专家,所以我不会深入讨论这个问题。但这肯定是有可能的。它只不过是在计时器的tick函数中实现当前的shot方法。当然,删除for i最后我在bullet类中添加了一个计时器,并在paintcomponent方法中重新绘制
package game;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Bullet {
private int x, y;
private int speed, ttl;
public final Timer timer1;
public Bullet(int x, int y, int speed){
this.x = x;
this.y = y;
this.speed= speed;
this.ttl = 250;
ActionListener actListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Move();
}
};
this.timer1 = new Timer(50, actListener);
timer1.start();
}
public int getdy(){
return y;
}
public void setdy(int newy){
y = newy;
}
public int getdx(){
return x;
}
public int Move(){
//Do some calculation to perform loss of velocity within a reasonable range. Because these number might be overkill
this.speed -= (ttl / 100);
y += this.speed;
ttl--;
return y;
}
}
您应该为动画使用javax.swing.Timer请参见:。另外,不要从paintComponent方法调用repaint。@ControlAltDel Thx,但是您能解释一下有关计时器的更多信息吗?我应该如何使用计时器?@camickr Thx,为什么不调用重绘?你是说在我的for循环中吗?!太多了!我不想写专业的东西!所以我决定使用JPanel。链接很有用!你完全忽略了一个事实,那就是问题是关于如何在摇摆中进行的,因此你的答案在这里是完全错误的。在Swing这样的事件驱动系统中,经典的游戏循环是个坏主意。您关于Cancas vs JPanel的信息不完整且不正确,而且它没有解决根本问题。我添加了一个编辑,以便@Ebola知道如何使用JPanel或Canvas。如果他使用你所展示的速度修改器,那么每次他们调用shot方法时,它只会使子弹移动一次。他们需要一种让子弹不断移动的方式。嗨,谢谢!很好,但是有个问题!当我开枪时,第一颗子弹在下一颗子弹发射之前不会移动!你也能帮我吗?!我用了你写的代码!您应该将bullet类引用存储在数组列表中。在主游戏循环中,您应该调用shot函数。这将解决问题。@Syntasu我使用了一个arraylist来存储子弹,但它不起作用!在页面顶部查看我的代码!在paintcomponent类中!我做错了吗?在当前帖子下添加了一个新的更新部分。希望这能回答您的问题:
public void shoot(){
if(bullets != null){
for(int i=0; i<bullets.size(); i++){
bullets.get(i).Move();
}
}
}
@Override
public void paintComponent(Graphics grphcs)
{
super.paintComponent(grphcs);
Graphics2D gr = (Graphics2D) grphcs;
int X = (int) rec.getCenterX();
int Y = (int) rec.getCenterY();
gr.drawImage(imageBg, 0, 0, null);
gr.drawImage(imageFi, X-50, Y-75, null);
gr.setColor(Color.GRAY);
if(bullets != null)
{
for(int i=0;i<bullets.size();i++)
{
//Here is were we loop over the bullet list, lets add the move method
bullets.get(i).Move();
gr.drawImage(imageBu, null, bullets.get(i).getdx(), bullets.get(i).getdy());
repaint();
}
}
gr.draw(recB);
}
for(int i=0;i<bullets.size();i++)
{
Bullet b = bullets.get(i);
if(b.ttl >= 1)
{
bullets.get(i).Move();
gr.drawImage(imageBu, null, b.getdx(), b.getdy());
}
else
{
//Remove the bullet from the list
//In C# its bullets.Remove(b);
}
repaint();
}
package game;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Bullet {
private int x, y;
private int speed, ttl;
public final Timer timer1;
public Bullet(int x, int y, int speed){
this.x = x;
this.y = y;
this.speed= speed;
this.ttl = 250;
ActionListener actListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Move();
}
};
this.timer1 = new Timer(50, actListener);
timer1.start();
}
public int getdy(){
return y;
}
public void setdy(int newy){
y = newy;
}
public int getdx(){
return x;
}
public int Move(){
//Do some calculation to perform loss of velocity within a reasonable range. Because these number might be overkill
this.speed -= (ttl / 100);
y += this.speed;
ttl--;
return y;
}
}