I´m building my own Space Invaders in Java with Greenfoot and I have a Spaceship which shoots the Aliens, but the Bullets stop at the top of the map and stay there so I wrote this method which should remove a bullet if it hits the top of the but it doesn't work. What´s the problem?
public void disappearIfOnTop() {
Actor Bullet = getOneIntersectingObject(Actor.class);
getY();
if(getY() == 0) {
World world;
world = getWorld();
world.removeObject(Bullet);
}
}
Edit: they are getting removed if they hit another bullet which is stuck on the top.
The method getOneIntersectingObject() returns a null if there is no other actor.
You might want to check this to be sure:
public void disappearIfOnTop() {
if (getY() == 0) {
Actor bullet = getOneIntersectingObject(Actor.class);
if (bullet == null) {
setLocation(getX(), 50); // move down if no other is around
} else {
setLocation(getX(), 100); // move further down if another is around
}
}
}
If the method getOneIntersectingObject() returns a reference to an actor, your current method is removing that one, not the one who is at Y=0. (BTW, don't use variable names starting with uppercase letters. By convention, this is reserved for classes.)
You can simplify your method to:
public void disappearIfOnTop() {
if (getY() == 0) {
getWorld().removeObject(this);
}
}
Related
I'm working on a game in java, based on the Atari game adventure. I got the basic KeyListener part working fine, but then I added another if statement, using another class, to test if if the player was going to hit a wall, and stopping movement if that was the case. The method I used also used if statements, and when I ran the code, it had MAJOR lag. I tried a while loop first, but that made it lag even worse. Anyway to make this not lag so much? It doesn't seem that complex a program to run, and I still have to add yet another if statement to make be able to move into another room, so I have to do something to massively cut down on the lag.
Here is the class:
class Player extends JPanel implements KeyListener{
private char c = 'e';
int x = 400;
int y = 400;
int mapX = 0;
int mapY = 0;
public Player() {
this.setPreferredSize(new Dimension(800, 500));
addKeyListener(this);
}
public void addNotify() {
super.addNotify();
requestFocus();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Environment Layout = new Environment();
Layout.drawRoom(mapX,mapY,g);
g.fillRect(x , y , 20, 20);
}
public void keyPressed(KeyEvent e) { }
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) {
c = e.getKeyChar();
repaint();
Environment Layout = new Environment();
if(Layout.isWall(x,y,c)){}
else{
if (c == 'a'){
x = x - 3;
}
else if (c == 'w'){
y = y - 3;
}
else if (c == 's'){
y = y + 3;
}
else if (c == 'd'){
x = x + 3;
}
}
}
public static void main(String[] s) throws IOException{
JFrame f = new JFrame();
f.getContentPane().add(new Player());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
The draw room method I used in this was just to put the background of the room into place.
Here is the isWall method from the Environment class:
public boolean isWall(int moveX, int moveY, char let){
BufferedImage room = null;
try {
room = ImageIO.read(new File(xNum + "," + yNum + ".png"));
}
catch (IOException e) {
}
int[][] walls = convertImage(room);
boolean blocked = false;
if(let == 'w') {
if(walls[moveY-8][moveX] == -3584){blocked = true;}
}
else if(let == 's') {
if(walls[moveY+20][moveX] == -3584){blocked = true;}
}
else if(let == 'a') {
if(walls[moveY][moveX-5] == -3584){blocked = true;}
}
else if(let == 'd') {
if(walls[moveY][moveX+20] == -3584){blocked = true;}
}
return blocked;
}
the convertImage method just converts the image of the room into an int array, for the value of the colors. -3584 is the color of the walls. It's possible this is what's lagging it, but this seemed like the best way for each room to have the walls done automatically.
I also tried a timer, but either I did that wrong, or it just didn't help.
I can give more of my code if that's needed, but help with this would be much appreciated. I'm relatively new to this kind of stuff, so it's likely I'm missing something big. Thanks.
The lag here is almost certainly not from the if statements. Those are really fast. I think the bigger issue is in isWall. Notice that any time you want to check for whether a wall is present, you
Open a file,
read the file contents,
convert the file contents from an image to a grid of pixels, and
read exactly one pixel.
Reading files from disk is extremely slow compared to looking at values in memory. For example, a regular magnetic hard drive works at around 7200 RPM, so the seek time is measured in milliseconds. On the other hand, your processor can do about a billion operations per second, so other operations take nanoseconds. That means that a disk read is roughly a million times slower than other operations, which is almost certainly where you're getting the lag from!
To fix this, consider rewriting your isWall code so that you only read the file and do the conversion once and, having done that, then just look up the part of the image you need. This converts doing tons of (glacially slow) file reads to one single (slow but inevitable) file read followed by tons of fast memory reads.
You appear to be moving your walls further than you are moving your player.
Is it possible that your player object is getting stuck in a wall there by producing "blocked = true" continuously?
Your character gets +- 3 in every direction, however your walls seem inconsistent and range from 8 up to 20 down to 5 left to 20 right.
This is an extension to #templatetypedef's answer.
Instead of loading the image files upon calling the isWall method, you might want to consider caching all of the walls on game start.
So I am thinking;
have a HashMap data structure keyed by <String, Integer>. Where String is your coordinates. E.g. coordinate string = "100,238"
parse all the .png image files in the directories and store the coordinates as key and the value can just be any dummy value like 1 or 2.
Then when isWall() is invoked. Given the X and Y coordinate, build the coordinate string as mentioned in point 1 and check if the key exists. If it does then we know it is a piece of wall else not.
This should drastically reduce the I/O disk contention.
In future, if you would like to extend the solution to incorporate APIs like isTreasureChest() or isMonster(). It can be extended by building a immutable class call "Room" or "Tile" to represent the object. Then modify the HashMap to take in <String, Room>.
I'm currently trying to make a small Entity-Relationship-Modell creating tool for Databases.
To avoid errors I try to don't allow the rectangles to overlap with a other rectangle.
I got most of my code working and it detects almost every collusion but in one case I can still overlap them and I don't know how to fix this error.
The problem is that it will look on only on rectangle not on both. But I really don't know how to intercept that case.
The strange thing to me is that my Debug line
System.out.println("still intersects?");
never triggers. Can somebody help me out in this error?
Image to the error in my Colision
This Function gets triggered every time I move a Rectangle.
The attribute Selected is a Boolean which says me which Rectangle I'm moving.
Then I check on which side its overlapping and revert back to the old position.
boolean Move(Point point) {
boolean moved = false;
boolean foundone = false;
for (ERMRectangle rectangle : Rectangles) {
if (rectangle.selected) {
foundone = true;
moved = true;
//calculated new Rectangle after Move
Rectangle Temp = new Rectangle();
Temp.x = point.x + rectangle.click.x;
Temp.width = rectangle.position.width;
Temp.height = rectangle.position.height;
Temp.y = point.y + rectangle.click.y;
for (ERMRectangle rectangle2 : Rectangles) {
if (rectangle != rectangle2 && rectangle2.position.intersects(Temp))//prevent overlapping
{
Rectangle intersection = rectangle2.position.intersection(Temp);
if (intersection.height > intersection.width) {
Temp.x = rectangle2.position.x - rectangle2.position.width;
if (intersection.x != rectangle2.position.x) {
Temp.x = rectangle2.position.x + rectangle2.position.width;
}
} else {
Temp.y = rectangle2.position.y - rectangle2.position.height;
if (intersection.y != rectangle2.position.y) {
Temp.y = rectangle2.position.y + rectangle2.position.height;
}
}
}
if(rectangle != rectangle2 && rectangle2.position.intersects(Temp))
{
System.out.println("still intersects?");
}
}
rectangle.position = Temp;
}
}
return moved;
}
ERMRectangle class:
import java.awt.Rectangle;
public class ERMRectangle {
public Rectangle position;
public boolean selected;
public Point click;
}
Edit: i resolved it by adding one more for loop into my methode which checks if it still interselects the rectangle and reverts both x and y cordinnates.
If at any moment, there will only be one rectangle moving (dragged by the user) there is no need to use nested loops to check for collision n-square times.
All you need is a method like this in your ERMRectangle class:
These codes assume your ERMRectangle class extends Rectangle class from Java
public boolean isColliding(ArrayList<ERMRectangle> rects)
{
for(ERMRectangle r : rects)
if(this != r && this.intersects(r))
return true;
return false;
}
You can then invoke isColliding() in the mouseReleased(MouseEvent e) in the mouse listener for your rectangles, and trigger the necessary actions when collision is detected. So, upon every mouse release after dragging, it will check for collisions on the rectangle which you have just moved.
To check for collision as you drag, place the similar codes as you would in mouseReleased(MouseEvent e) into mouseDragged(MouseEvent e). This will do a real-time collision detection check as you drag the rectangle.
I'm trying to make a little game, where you have a little cube you can control with the arrows. When the cube intersects with another block object, I want it to go back and stop by the edge of the block object. So basically I want my block to stop when it intersects the block object, instead, it moves a bit in to it, and then when I move it again it jumps back. How can I make it so first checks if it will intersect, and if it will not move into it?
My drawing class extends JPanel and I'm painting with paintComponent.
if(keyCode == e.VK_RIGHT) {
if(xRightCollision()){
hero.x -= xVel;
}
else {
hero.x += xVel;
}
}
So let's say the cube is at the edge of the block object, but it's not intersecting it yet, so I press right and it moves into it, I press right again and it jumps back 5 pixels(xVel = 5).
public boolean xRightCollision(){
for(int i = 0; i < obstacles.size(); i++) {
if (hero.intersects(obstacles.get(i))) {
return true;
}
}
return false;
}
I've actually tried a similar thing with paint() on the JFrame, and since you have to call repaint() there, I could check first and then repaint. I don't really understand how paintComponent works since you can't control when it should be repainted.
Just use a temporary value to check, if the cube intersects with an obstacle, and reset to the original position, if necessary:
if(keyCode == e.VK_RIGHT) {
//backup of the cubes position
int tmp = hero.x;
//move the hero to the right
hero.x += xVel;
if(xRightCollision())
//cube intersects with an obstacle -> restore original position
hero.x = tmp;
}
In my maze game applet I'm having a little bug. Collision detection works but sometimes my character can go into walls. More precisely it detects collision and moves the character into the wall. It happens very rare but still pretty annoying. It happens if I keep pressing the arrow keys too fast alternately (for example down and right in a corner). The thread sleeps 20ms if that matters and a tile is 20px*20px.
I think the bug is somewhere here.
Rect is around the character 20*20px and bigRect is 60*60px to check collision in advance and r is around the wall tiles also 20*20px.
public void checkCollision() {
if (r.intersects(Hero.getBigRect()) && Hero.getRect().intersects(r)) {
if (hero.isMovingUp() == true) {
hero.stopUp();
hero.setHeroY(tileY + 20);
}
if (hero.isMovingDown() == true) {
hero.stopDown();
hero.setHeroY(tileY - 20);
}
if (hero.isMovingLeft() == true) {
hero.stopLeft();
hero.setHeroX(tileX + 20);
}
if (hero.isMovingRight() == true) {
hero.stopRight();
hero.setHeroX(tileX - 20);
}
}
}
I'm working on a pacman clone in java using eclipse and sometimes it appears laggy more specifically the movement of pacman/ghosts is slow, sometimes its fine. Once it has happened while I was running it so it wasn't after I added code and it doesn't seem to be after any specific event in game. I can't find any trigger or produce the lag on purpose
The resource manager shows the same cpu usage(only around 50%)/memory usage . Aswell the FPS seems to be around 200 consistently through lag and during the periods where it is working well.
Does anyone know what this could be?
Is there any information I left out that could be of use?
edit - I am basing movement on a timer is that bad? I will post the movement relevant code below is there a good way of posting the whole code on here?
Timer movement = new Timer(20, new ActionListener()//500 is time in milliseconds between
//calls to actionPerformed as far as I know.
{
public void actionPerformed(ActionEvent arg0)
{
if(movingUp == true)
{
moveUp();
}
else if(movingDown == true)
{
moveDown();
}
else if(movingRight == true)
{
moveRight();
}
else if(movingLeft == true)
{
moveLeft();
}
}
});
public void moveUp()
{
yPos -= 1;
this.rect.y -= 1;
}
public void setDirUp()
{
movingUp = true;
movingDown = false;
movingRight = false;
movingLeft = false;
}
in the main class in public void keyPressed:
if(keyCode == KeyEvent.VK_W)
{
if(pacMan.isUpHittingWall == false)
{
pacMan.setDirUp();
pacMan.isDownHittingWall = false;
pacMan.isRightHittingWall = false;
pacMan.isLeftHittingWall = false;
}
}
edit 2 -Thanks for the help guys. I have the movement using System time now and it seems to have fixed the issue because I implemented it only for pacman at first and the ghosts were still slow. Now there is an issue where moving right and down are much slower than moving left or up The only difference I see is that right and down are both adding and left and up are subtracting. What can I do about this?
The updated code is below.
//updated movement code
public void moveUp(long timePassed)
{
yPos -= vy * timePassed;
this.rect.y -= vy * timePassed;
}
public void moveDown(long timePassed)
{
yPos += vy * timePassed;
this.rect.y += vy * timePassed;
}
public void moveRight(long timePassed)
{
xPos += vx * timePassed;
this.rect.x += vx * timePassed;
}
public void moveLeft(long timePassed)
{
xPos -= vx * timePassed;
this.rect.x -= vx * timePassed;
}
//I passed timePassed through a globalInputObject because my input is handled in public //void keyPressed(KeyEvent e) and I didnt know how else to get timePassed in to the //movement method
//Here is the code in gameLoop()
globalInputObject.isPacManMovingUp(timePassed);
globalInputObject.isPacManMovingDown(timePassed);
globalInputObject.isPacManMovingRight(timePassed);
globalInputObject.isPacManMovingLeft(timePassed);
//This is inside the GlobalInputObject
public void isPacManMovingUp(long timePassed)
{
if(pacMan.movingUp == true)
{
pacMan.moveUp(timePassed);
}
}
public void isPacManMovingDown(long timePassed)
{
if(pacMan.movingDown == true)
{
pacMan.moveDown(timePassed);
}
}
public void isPacManMovingRight(long timePassed)
{
if(pacMan.movingRight == true)
{
pacMan.moveRight(timePassed);
}
}
public void isPacManMovingLeft(long timePassed)
{
if(pacMan.movingLeft == true)
{
pacMan.moveLeft(timePassed);
}
}
Rather than always moving the pacman by a constant distance (1 pixel, it appears) each time the timer runs, you should:
Set the timer to run as fast as possible (e.g. once every millisecond or less). Edit: if you set it too fast, the game may end up actually running slower, you'll have to experiment.
Calculate how much time has passed between each frame using the system clock and move the pacman by an amount proportional to that.
Doing the above will mean that if the system is "laggy," it will simply show fewer frames per second, rather than actually moving everything slower.
As I feared, you're basing the distance moved on the time chunk from the Timer. You shouldn't do this as all timers can be variable and unreliable, especially with small time chunks. Better to base movement on difference in system time. So yes, use a Timer or something to run your "game loop", but know the sprite's position and velocity using doubles, and calculate the distance to move based on velocity vector (math vector not Java Vector) * difference in system time. That way if the timer is delayed by say garbage collection, making the time chunk larger, the distance moved will be correspondingly greater and will look smoother.
You should look into creating a proper "main loop" or "game loop" as some call it. Take a look at the game structure part of this wikipedia article.. Basically those input events are happening\invoked from a separate thread than the main thread and they are directly modifying geometry of in game objects. Instead consider something like this for a main loop:
loop:
process collision detection
process animation (alters geometry of game objects)
process input (more on this later)
any other game specific logic
render screen
your process input could be something like this
if (globalInputObject.movingUp==true) {
hero.y -= 10;
}
if (globalInputObject.movingDown==true) {
hero.y += 10;
}
if (globalInputObject.movingLeft==true) {
hero.x -= 10;
}
if (globalInputObject.movingRight==true) {
hero.x += 10;
}
and your input handler would look something like this:
public void actionPerformed(ActionEvent evt) {
if (evt.button==UP_BUTTON) {
globalInputObject.movingUp=true;
}
if (evt.button==DOWN_BUTTON) {
globalInputObject.movingDown=true;
}
if (evt.button==LEFT_BUTTON) {
globalInputObject.movingLeft=true;
}
if (evt.button==RIGHT_BUTTON) {
globalInputObject.movingRight=true;
}
}
Basically the processing that you're doing in your "extra" threads (input thread) is minimal and therefore doesn't interfere with your main thread. Also, this method has the benefied of easily supporting multiple directions simultaneously (ie: UP+RIGHT = diagonal).
Only super high end games have more than a single thread (if they even need it at all). Dealing with synchronisation in a game is not good for performance.