我使用Bucky的光滑Java教程做了一个简单的2D状态更改游戏,我修改了这个游戏,现在想在地图上设置碰撞,这样我的玩家就无法通过地图上的房子。我想我对碰撞的工作原理有所了解:
使用以下代码制作2个矩形:
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
1为播放器,1为障碍物,我如何将其放入我的代码中?如何告诉java障碍物的矩形与播放器矩形不同?
然后在制作了2个矩形之后,我会设置一个if语句,说如果相交就行了......
希望在此之后我觉得它会起作用。关于游戏的一些更多信息,它是一个状态改变游戏,它有一些方法,如init,渲染和更新的方法(我在哪里放置我的矩形和if语句,在更新方法中?),它还是一个顶上视图游戏有点像口袋妖怪,如果这有帮助。如果您需要我的代码,请询问,我现在不想让它过度拥挤这篇文章。
EDIT1:
package javagame;
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;
public class Play extends BasicGameState{
Animation bucky, movingUp, movingDown, movingLeft, movingRight, movingBL, movingBR, movingFL, movingFR;
Image worldMap;
boolean quit = false;//gives user to quit the game
int[] duration = {200, 200};//how long frame stays up for
float buckyPositionX = 0;
float buckyPositionY = 0;
float shiftX = buckyPositionX + 320;//keeps user in the middle of the screem
float shiftY = buckyPositionY + 160;//the numbers are half of the screen size
public Play(int state){
}
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
worldMap = new Image("res/world.png");
Image[] walkUp = {new Image("res/b.png"), new Image("res/b.png")}; //these are the images to be used in the "walkUp" animation
Image[] walkDown = {new Image("res/f.png"), new Image("res/f.png")};
Image[] walkLeft = {new Image("res/l.png"), new Image("res/l.png")};
Image[] walkRight = {new Image("res/r.png"), new Image("res/r.png")};
Image[] walkBL = {new Image("res/bl.png"), new Image("res/bl.png")};
Image[] walkBR = {new Image("res/br.png"), new Image("res/br.png")};
Image[] walkFL = {new Image("res/fl.png"), new Image("res/fl.png")};
Image[] walkFR = {new Image("res/fr.png"), new Image("res/fr.png")};
movingUp = new Animation(walkUp, duration, false);
movingDown = new Animation(walkDown, duration, false);
movingLeft = new Animation(walkLeft, duration, false);
movingRight = new Animation(walkRight, duration, false);
movingBL = new Animation(walkBL, duration, false);
movingBR = new Animation(walkBR, duration, false);
movingFL = new Animation(walkFL, duration, false);
movingFR = new Animation(walkFR, duration, false);
bucky = movingDown;//facing screen initially on startup
}
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
worldMap.draw(buckyPositionX, buckyPositionY);//position 0,0
bucky.draw(shiftX, shiftY);//makes him appear at center of map
g.drawString("Suraj's X: "+buckyPositionX+"\nSuraj's Y: "+buckyPositionY,400,20);//tells us the position
if(quit==true){
g.drawString("Resume(R)", 250, 100);
g.drawString("Main(M)", 250, 150);
g.drawString("Quit Game(Q)", 250, 200);
if(quit==false){
g.clear();//wipe off everything from screen
}
}
}
public void update(GameContainer gc, StateBasedGame sbg, int delta)throws SlickException{
Input input = gc.getInput();
//up
if(input.isKeyDown(Input.KEY_UP)){
bucky = movingUp;//changes the image to his back
buckyPositionY += 10;;//increase the Y coordinates of bucky (move him up)
if(buckyPositionY>162){//if I reach the top
buckyPositionY -= 10;//stops any further movement in that direction
}
}
//down
if(input.isKeyDown(Input.KEY_DOWN)){
bucky = movingDown;
buckyPositionY -= 10;
if(buckyPositionY<-600){
buckyPositionY += 10;//basically change the direction if + make -
}}
//left
if(input.isKeyDown(Input.KEY_LEFT)){
bucky = movingLeft;
buckyPositionX += 10;
if(buckyPositionX>324){
buckyPositionX -= 10;//delta * .1f
}}
//right
if(input.isKeyDown(Input.KEY_RIGHT)){
bucky = movingRight;
buckyPositionX -= 10;
if(buckyPositionX<-840){
buckyPositionX += 10;
}}
//2 key combos start here
if(input.isKeyDown(Input.KEY_RIGHT) && input.isKeyDown(Input.KEY_UP)){
bucky = movingBR;
buckyPositionX -= delta * .1f;
if(buckyPositionX<-840){
buckyPositionX += delta * .1f;
if(buckyPositionY>162){
buckyPositionY -= delta * .1f;
}}}
if(input.isKeyDown(Input.KEY_LEFT) && input.isKeyDown(Input.KEY_UP)){
bucky = movingBL;
buckyPositionX -= delta * .1f;
if(buckyPositionX>324){
buckyPositionX -= delta * .1f;
if(buckyPositionY>162){
buckyPositionY -= delta * .1f;
}}}
if(input.isKeyDown(Input.KEY_RIGHT) && input.isKeyDown(Input.KEY_DOWN)){
bucky = movingFR;
buckyPositionX -= delta * .1f;
if(buckyPositionY<-600){
buckyPositionY += delta * .1f;
if(buckyPositionX<-840){
buckyPositionX += delta * .1f;
}}}
if(input.isKeyDown(Input.KEY_LEFT) && input.isKeyDown(Input.KEY_DOWN)){
bucky = movingFL;
buckyPositionX -= delta * .1f;
if(buckyPositionY<-600){
buckyPositionY += delta * .1f;
if(buckyPositionX>324){
buckyPositionX -= delta * .1f;
}}}
//escape
if(input.isKeyDown(Input.KEY_ESCAPE)){
quit=true;
}
//when the menu is up
if(quit==true){//is the menu on the screen
if(input.isKeyDown(Input.KEY_R)){
quit = false;//resumes the game, makes menu dissapear
}
if(input.isKeyDown(Input.KEY_M)){
sbg.enterState(0);//takes you to the main menu
}
if(input.isKeyDown(Input.KEY_Q)){
System.exit(0);//quits the game
}
}
}
public int getID(){
return 1;
}
}
这是我的Play类,我唯一的另外两个类是main和菜单,我无法想象在main或menu类中制作的矩形方法所以剩下的唯一一个是Play,但我不明白如何在我到目前为止的代码中制作2个不同的矩形(一个用于玩家,另一个用于房子)。如果您需要我的主菜单和菜单类,请告诉我。
编辑3:
我已经尝试了你所说的并制作了一个Rectanglebase类并把你发布的if sattement放在那里但是我遇到了错误,它要求我在我的播放器类中为getX和getY制作一个方法fornt的构造函数也有错误:
public Rectanglebase{}//the public is saying syntax error
我也像你说的那样建立了一个家庭和球员课程,但我对我需要投入的内容感到有点困惑,我把它归入了Home课程:
return Rectangle(100,100,100,100);
但是我遇到了错误,我不确定这是否正确。 另外,在x,y的播放器类中,如何设置我的Play类的浮点变量?
答案 0 :(得分:7)
以下是通过Rectangle2D#intersects(..)
方法的游戏循环 / 游戏逻辑和碰撞检测的示例。
它使用JPanel
绘制所有内容,Rectangle2D
用于Entity
类(这是需要绘制到GamePanel
的任何对象,这是我们的JPanel所有内容画了。)
updateGame()
方法是您可以找到碰撞检查的地方:
private void updateGame() {
if (entities.get(0).intersects(entities.get(1))) {
System.out.println("Intersecting");
}
....
}
你是玩家1 并移动 W , A , S , D 大骨节病>。当您与 Player 2 相交时,println()
将确认交叉点。
GameLogic.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
/**
*
* @author David Kroukamp
*/
public class GameLogic {
public GameLogic() {
initComponents();
}
final GamePanel gp = new GamePanel(500, 500);
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Entity entity1 = new Entity(100, 100, 100, 100, createWhiteImage());
Entity entity2 = new Entity(300, 200, 100, 100, createBlackImage());
gp.addEntity(entity1);
gp.addEntity(entity2);//just a standing still JPanel
setGamePanelKeyBindings(gp, entity1);
frame.add(gp);
frame.pack();
frame.setVisible(true);
//start the game loop which will repaint the screen
runGameLoop();
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop() {
Thread loop = new Thread(new Runnable() {
@Override
public void run() {
gp.running.set(true);
gp.gameLoop();
}
});
loop.start();
}
private void setGamePanelKeyBindings(GamePanel gp, final Entity entity) {
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "D pressed");
gp.getActionMap().put("D pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.RIGHT = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "A pressed");
gp.getActionMap().put("A pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.LEFT = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "W pressed");
gp.getActionMap().put("W pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.UP = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "S pressed");
gp.getActionMap().put("S pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.DOWN = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "D released");
gp.getActionMap().put("D released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.RIGHT = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"), "A released");
gp.getActionMap().put("A released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.LEFT = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "W released");
gp.getActionMap().put("W released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.UP = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"), "S released");
gp.getActionMap().put("S released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.DOWN = false;
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new GameLogic();
}
});
}
private BufferedImage createWhiteImage() {
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, img.getWidth(), img.getHeight());
return img;
}
private BufferedImage createBlackImage() {
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, img.getWidth(), img.getHeight());
return img;
}
}
class Entity extends Rectangle2D.Double {
private int speed = 5;
public boolean UP = false,
DOWN = false,
LEFT = false,
RIGHT = false;
private final BufferedImage image;
public Entity(int x, int y, int width, int height, BufferedImage image) {
super(x, y, width, height);
this.width = width;
this.height = height;
this.image = image;
}
public BufferedImage getImage() {
return image;
}
public void move() {
if (UP) {
y -= speed;
}
if (DOWN) {
y += speed;
}
if (LEFT) {
x -= speed;
}
if (RIGHT) {
x += speed;
}
}
}
class GamePanel extends JPanel {
private int width, height;
private int frameCount = 0;
private int fps = 0;
public static AtomicBoolean running = new AtomicBoolean(false), paused = new AtomicBoolean(false);
final ArrayList<Entity> entities = new ArrayList<>();
GamePanel(int w, int h) {
super(true);
setIgnoreRepaint(true);//mustnt repaint itself the gameloop will do that
setLayout(null);
width = w;
height = h;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void addEntity(Entity e) {
entities.add(e);
}
//Only run this in another Thread!
public void gameLoop() {
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while (running.get()) {
double now = System.nanoTime();
int updateCount = 0;
if (!paused.get()) {
//Do as many game updates as we need to, potentially playing catchup.
while (now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER) {
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if (now - lastUpdateTime > TIME_BETWEEN_UPDATES) {
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
drawGame();
lastRenderTime = now;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime / 1000000000);
if (thisSecond > lastSecondTime) {
System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
fps = frameCount;
frameCount = 0;
lastSecondTime = thisSecond;
}
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while (now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES) {
//allow the threading system to play threads that are waiting to run.
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
//On my OS it does not unpuase the game if i take this away
try {
Thread.sleep(1);
} catch (Exception e) {
}
now = System.nanoTime();
}
}
}
}
private void drawGame() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
repaint();
}
});
}
private void updateGame() {
if (entities.get(0).intersects(entities.get(1))) {
System.out.println("Intersecting");
}
for (Entity e : entities) {
e.move();
}
}
@Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
applyRenderHints(g2d);
g2d.setColor(Color.GREEN);
g2d.fillRect(0, 0, getWidth(), getHeight());
for (Entity e : entities) {
g2d.drawImage(e.getImage(), (int) e.getX(), (int) e.getY(), null);
}
g2d.setColor(Color.BLACK);
g2d.drawString("FPS: " + fps, 5, 10);
frameCount++;
}
private final static RenderingHints textRenderHints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
private final static RenderingHints imageRenderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
private final static RenderingHints colorRenderHints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
private final static RenderingHints interpolationRenderHints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
private final static RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
public static void applyRenderHints(Graphics2D g2d) {
g2d.setRenderingHints(textRenderHints);
g2d.setRenderingHints(imageRenderHints);
g2d.setRenderingHints(colorRenderHints);
g2d.setRenderingHints(interpolationRenderHints);
g2d.setRenderingHints(renderHints);
}
}
答案 1 :(得分:0)
if(house.getBounds().contains(player.getX(),player.getY()){//do something}
只要你的房子和你的玩家矩形在不同的类中定义,java就能分辨出来
首先创建一个类,它是处理矩形的基类:
public class Rectanglebase{
public void getBounds(){//write method}
//write other methods you will need to use for both rectangles here
public Rectanglebase{//default constructor}
}//end class definition
现在为房子和玩家写课:
public class House extends Rectanglebase{
//getBounds() is inherited, so just write stuff to do with the graphics of the house here
}
当您在主代码中生成房屋时,您可以自己创建:
House house = new House();
然后以类似的方式为玩家生成类,然后在主代码中构造:
Player player = new Player()
house
和player
是不同的变量,这就是java如何区分你的房子和玩家