I am having trouble serializing this class using the ObjectOutputStream#writeObject method.
Here is my class:
public class InteractedObject implements Serializable{
private static final long serialVersionUID = 537798409913313981L;
protected int id;
protected WorldTile tile;
protected int option;
private long interactionTime;
public InteractedObject(int id, WorldTile tile, int option){
this.id = id;
this.tile = tile;
this.option = option;
}
public long getInteractionTime(){
return interactionTime;
}
public void setInteractionTime(long interactionTime){
this.interactionTime = interactionTime;
}
public boolean isEqualTo(Object o){
if(this == o)
return true;
InteractedObject obj = o instanceof InteractedObject ? (InteractedObject)o : null;
if(obj == null)
return false;
return obj.id == id && obj.tile.equals(tile) && obj.option == option;
}
}
The WorldTile class definitely implements the Serializable interface and only uses fields with types short and byte. I cannot see why this throws a NotSerializableException for my class 'a.rodit.rs.InteractedObject' (the top one).
Any help or guidance about why this is happening would be appreciated.
EDIT:
My WorldTile class is as follows:
public class WorldTile implements Serializable {
private static final long serialVersionUID = -6567346497259686765L;
private short x, y;
private byte plane;
public WorldTile(){
this(0, 0, 0);
}
public WorldTile(int x, int y, int plane) {
this.x = (short) x;
this.y = (short) y;
this.plane = (byte) plane;
}
public final WorldTile getLocation() {
WorldTile tile = new WorldTile(x, y, plane);
return tile;
}
public WorldTile(WorldTile tile) {
this.x = tile.x;
this.y = tile.y;
this.plane = tile.plane;
}
public WorldTile(WorldTile tile, int randomize) {
this.x = (short) (tile.x + Utils.getRandom(randomize * 2) - randomize);
this.y = (short) (tile.y + Utils.getRandom(randomize * 2) - randomize);
this.plane = tile.plane;
}
public void moveLocation(int xOffset, int yOffset, int planeOffset) {
x += xOffset;
y += yOffset;
plane += planeOffset;
}
public final void setLocation(WorldTile tile) {
setLocation(tile.x, tile.y, tile.plane);
}
public final void setLocation(int x, int y, int plane) {
this.x = (short) x;
this.y = (short) y;
this.plane = (byte) plane;
}
public int getX() {
return x;
}
public int getXInRegion() {
return x & 0x3F;
}
public int getYInRegion() {
return y & 0x3F;
}
public int getY() {
return y;
}
public int getPlane() {
if (plane > 3)
return 3;
return plane;
}
public int getChunkX() {
return (x >> 3);
}
public int getChunkY() {
return (y >> 3);
}
public int getRegionX() {
return (x >> 6);
}
public int getRegionY() {
return (y >> 6);
}
public int getRegionId() {
return ((getRegionX() << 8) + getRegionY());
}
public int getLocalX(WorldTile tile, int mapSize) {
return x - 8 * (tile.getChunkX() - (Settings.MAP_SIZES[mapSize] >> 4));
}
public int getLocalY(WorldTile tile, int mapSize) {
return y - 8 * (tile.getChunkY() - (Settings.MAP_SIZES[mapSize] >> 4));
}
public int getLocalX(WorldTile tile) {
return getLocalX(tile, 0);
}
public int getLocalY(WorldTile tile) {
return getLocalY(tile, 0);
}
public int getLocalX() {
return getLocalX(this);
}
public int getLocalY() {
return getLocalY(this);
}
public int get18BitsLocationHash() {
return getRegionY() + (getRegionX() << 8) + (plane << 16);
}
public int get30BitsLocationHash() {
return y + (x << 14) + (plane << 28);
}
public boolean withinDistance(WorldTile tile, int distance) {
if (tile.plane != plane)
return false;
int deltaX = tile.x - x, deltaY = tile.y - y;
return deltaX <= distance && deltaX >= -distance && deltaY <= distance
&& deltaY >= -distance;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + plane;
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
WorldTile other = (WorldTile) obj;
if (plane != other.plane)
return false;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
public boolean withinDistance(WorldTile tile) {
if (tile.plane != plane)
return false;
// int deltaX = tile.x - x, deltaY = tile.y - y;
return Math.abs(tile.x - x) <= 15 && Math.abs(tile.y - y) <= 15;// deltaX
// <= 14
// &&
// deltaX
// >=
// -15
// &&
// deltaY
// <= 14
// &&
// deltaY
// >=
// -15;
}
public int getCoordFaceX(int sizeX) {
return getCoordFaceX(sizeX, -1, -1);
}
public static final int getCoordFaceX(int x, int sizeX, int sizeY,
int rotation) {
return x + ((rotation == 1 || rotation == 3 ? sizeY : sizeX) - 1) / 2;
}
public static final int getCoordFaceY(int y, int sizeX, int sizeY,
int rotation) {
return y + ((rotation == 1 || rotation == 3 ? sizeX : sizeY) - 1) / 2;
}
public int getCoordFaceX(int sizeX, int sizeY, int rotation) {
return x + ((rotation == 1 || rotation == 3 ? sizeY : sizeX) - 1) / 2;
}
public int getCoordFaceY(int sizeY) {
return getCoordFaceY(-1, sizeY, -1);
}
public int getCoordFaceY(int sizeX, int sizeY, int rotation) {
return y + ((rotation == 1 || rotation == 3 ? sizeX : sizeY) - 1) / 2;
}
}
As I mentioned previously, I don't see any problem with it.
NotSerializableException is only thrown when some object to be serialized does not implement the java.io.Serializable interface
I tried to simulate the issue and copied your class. Then I created a sample WorldTile class that looks like that:
public class WorldTile implements Serializable {
short x = 4;
byte y = 1;
}
My piece of code is as follows and it works well:
File file = new File("obj.txt");
file.createNewFile();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(new InteractedObject(4, new WorldTile(), 5));
System.out.println("success");
The only reason for you to fail to achieve this is probably your WorldTile class.
EDIT:
Another problem can be if you have failed to run the latest version of your file. Have you saved all the .java files in your application?
Also are you sure that your Serializable interface you have implemented is indedd java.io.Serializable ?
Related
Rectangle is formed using on this test
#Test
public void testRectangle1() {
Point center = new Point(20, 30);
Rectangle rect = new Rectangle(center, 20, 20);
assertAll(
() -> assertEquals(10, rect.getTopLeft().getX()),
() -> assertEquals(20, rect.getTopLeft().getY()),
() -> assertEquals(30, rect.getBottomRight().getX()),
() -> assertEquals(40, rect.getBottomRight().getY()),
() -> assertEquals(20, rect.getWidth()),
() -> assertEquals(20, rect.getHeight())
);
}
I already have class for point it should work correctly i mostly add it for understanding.
public class Point {
private int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public Point() {
this(0, 0);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void moveTo(int newX, int newY) {
x = newX;
y = newY;
}
public void moveRel(int dx, int dy) {
x += dx;
y += dy;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point other = (Point) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
So i stuck in second class for rectangle itself. First of all i kinda have hard time forming consructor that will form rectangle itself. And also on filling methods in rectangle class, as i have hard time in uderstanding what they should return becouse i have little experience in Java and coding.
public class Rectangle {
public int width = 0;
public int height = 0;
public Point center;
public Rectangle(Point center, int width, int height) {
int x = 0;
int y = 0;
width=x;
height=y;
}
public Point getTopLeft() {
Point point = new Point();
return point;
}
public Point getBottomRight() {
Point point = new Point();
return point;
}
public int getWidth() {
int x = 0;
return x;
}
public int getHeight() {
int y = 0;
return y;
}
}
In getTopLeft() and getBottomRight() you could create a point with center coordinates and then moveRel(int, int) it by width and height divided by 2, as you center point is in the middle of the both.
public Point getTopLeft() {
Point point = new Point(center.getX(), center.getY());
point.moveRel(- width / 2, height / 2);
return point;
}
public Point getBottomRight() {
Point point = new Point(center.getX(), center.getY());
point.moveRel(width / 2, - height / 2);
return point;
}
Constructor should write given values to the fields of the class.
Also consider using decimal type for the coordinates, only even height and width would be divisible by 2.
In my code I have a player class and from that Player class I want to call in a projectile, but whenever I try calling in the projectile in game, I get this error
Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at ca.runner.level.Level.tick(Level.java:127)
at ca.runner.game.Game.tick(Game.java:149)
at ca.runner.game.Game.run(Game.java:118)
at java.lang.Thread.run(Unknown Source)
I think it has to do maybe with the fact that both Mob and Projectile both call Entity or something like that, but I'm not sure how to fix this. If anyone could help that would be great.
Player Class:
package ca.runner.game.entities;
import ca.runner.game.Game;
import ca.runner.game.InputHandler;
import ca.runner.gfx.Colours;
import ca.runner.gfx.Screen;
import ca.runner.level.Level;
import ca.runner.game.InputHandler;
import ca.runner.gfx.Colours;
import ca.runner.gfx.Screen;
import ca.runner.level.Level;
public class Player extends Mob{
private InputHandler input;
private int colour = Colours.get(-1, 111, 145, 543);
private int scale = 1;
protected boolean isSwimming = false;
private int tickCount = 0;
private int health = 10;
public Player(Level level, int x, int y, InputHandler input) {
super(level, "Player", x, y, 1);
this.input = input;
this.health = health;
}
public void tick() {
int xa = 0;
int ya = 0;
if(input.up.isPressed()) {ya--;}
if(input.down.isPressed()) {ya++;}
if(input.left.isPressed()) {xa--;}
if(input.right.isPressed()) {xa++;}
if(input.space.isPressed()) {
BasicAttack Fireball = new BasicAttack(level, false, "Fireball", 10, 10, 1, 1, 1, getPlayerMoveDir());
level.addEntity(Fireball);
}
if (xa != 0 || ya != 0) {
move(xa, ya);
isMoving = true;
}else {
isMoving = false;
}
if (level.getTile(this.x >> 3, this.y >> 3).getId() == 4) {
isSwimming = true;
}
if (isSwimming && level.getTile(this.x >> 3, this.y >> 3).getId() != 4) {
isSwimming = false;
}
tickCount++;
}
public void render(Screen screen) {
int xTile = 0;
int yTile = 28;
int walkingSpeed = 4;
int flipTop = (numSteps >> walkingSpeed) & 1;
int flipBottom = (numSteps >> walkingSpeed) & 1;;
if (movingDir == 1) {
xTile += 2;
} else if (movingDir > 1) {
xTile += 4 + ((numSteps >> walkingSpeed) & 1) * 2;
flipTop = (movingDir - 1) % 2;
}
int modifier = 8 * scale;
int xOffset = x - modifier / 2;
int yOffset = y - modifier / 2 - 4;
if (isSwimming) {
int waterColour = 0;
yOffset += 4;
if (tickCount % 60 < 15) {
waterColour = Colours.get(-1, -1, 225, -1);
} else if (15 <= tickCount % 60 && tickCount % 60 < 30) {
yOffset -= 1;
waterColour = Colours.get(-1, 225, 115, -1);
} else if (30 <= tickCount % 60 && tickCount % 60 < 45) {
waterColour = Colours.get(-1, 115, -1, 225);
} else {
yOffset -= 1;
waterColour = Colours.get(-1, 225, 115, -1);
}
screen.render(xOffset, yOffset+3, 0 + 27 * 32, waterColour, 0x00, 1);
screen.render(xOffset + 8, yOffset+3, 0 + 27 * 32, waterColour, 0x01, 1);
}
//Upper Body
screen.render(xOffset + (modifier * flipTop), yOffset, xTile + yTile * 32, colour, flipTop, scale);
screen.render(xOffset + modifier - (modifier * flipTop), yOffset, (xTile + 1) + yTile * 32, colour, flipTop, scale);
if (!isSwimming) {
//Lower Body
screen.render(xOffset + (modifier * flipBottom), yOffset + modifier, xTile + (yTile+1) * 32, colour, flipBottom, scale);
screen.render(xOffset + modifier - (modifier * flipBottom), yOffset + modifier, (xTile+1) + (yTile+1) * 32, colour, flipBottom, scale);
}
}
public boolean hasCollided(int xa, int ya) {
int xMin = 0;
int xMax = 7;
int yMin = 3;
int yMax = 7;
for (int x = xMin; x < xMax; x++) {
if (isSolidTile(xa, ya, x, yMin)) {
return true;
}
}
for (int x = xMin; x < xMax; x++) {
if (isSolidTile(xa, ya, x, yMax)) {
return true;
}
}
for (int y = yMin; y < yMax; y++) {
if (isSolidTile(xa, ya, xMin, y)) {
return true;
}
}
for (int y = yMin; y < yMax; y++) {
if (isSolidTile(xa, ya, xMax, y)) {
return true;
}
}
return false;
}
public int getPlayerHealth() {
return health;
}
public int getPlayerMoveDir() {
return movingDir;
}
}
Projectile Class:
package ca.runner.game.entities;
import ca.runner.level.Level;
import ca.runner.level.tiles.Tile;
public abstract class Projectile extends Entity{
protected String name;
protected int speed;
protected int numSteps = 0;
protected boolean isMoving;
protected int movingDir = 1;
protected int scale;
protected int damage;
protected boolean emitter;
protected int moveDir;
public Projectile(Level level, boolean isEmitter, String name, int x, int y, int speed, int damage, int scale, int MoveDir) {
super(level);
this.name = name;
this.x = x;
this.y = y;
this.speed = speed;
this.damage = damage;
this.emitter = isEmitter;
this.scale = scale;
this.moveDir = moveDir;
}
public boolean isEmitter() {
return emitter;
}
public void move(int xa, int ya) {
//if(!hasCollided(xa, ya)) {
x+= xa * speed;
y += ya * speed;
//} else {
// level.removeEntity(this);
//}
}
//public abstract boolean hasCollided(int xa, int ya);
protected boolean isSolidTile(int xa, int ya, int x, int y) {
if (level == null) { return false;}
Tile lastTile = level.getTile((this.x + x) >> 3, (this.y + y) >> 3);
Tile newTile = level.getTile((this.x + x + xa) >> 3, (this.y + y + ya) >> 3);
if (!lastTile.equals(newTile) && newTile.isSolid()) {
return true;
}
return false;
}
public String getName() {
return name;
}
}
EDIT: Added the full stacktrace
I would guess that the addEntity method of the Level class adds the Fireball to a collection.
The "tick" method in your Player class is probably overriding a tick method in the "Mob" class that is called from something that loops over the same collection that addEntity wants to add to.
Have a look at the documentation for your iterator, it will tell you that it throws the "ConcurrentModificationException" if someone modifies the collection while it is iterating across it.
I can think of several ways to solve the problem.
Add the Fireball to a list of things to be added to your collection after the tick is done.
Keep some kind of reference to the iterator that you can call to make the addition. (Feels like a involved solution since you might need to handle "inTick" and "outsideTick" differently.
Iterate over the collection using an old-style "getAt" to retrieve the values. This will mean you are responsible for the concurrency yourself.
I hope this helps.
im really new in Java. I just need to explain how to declare 2D array of objects, i have something like:
package breakout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
public class Breakout extends JPanel {
public class Ball {
private
int x = 400;
int y = 300;
int speed = 2;
int dirx = 1;
int diry = -1;
public
void bounce(int px, int py, int lx, int ly) {
if ((x + 10 >= 800 && dirx == 1) || (x <= 0 && dirx == -1))
dirx *= -1;
if (y <= 0 && diry == -1)
diry *= -1;
if (y + 10 >= py && y <= py + ly && diry == 1 && x + 10 >= px && x <= px + lx)
diry *= -1;
}
int getX() {
return x;
}
int getY() {
return y;
}
void setDirx(){
dirx *= -1;
}
void setDiry(){
diry *= -1;
}
void move() {
x += speed*dirx;
y += speed*diry;
}
void paint(Graphics2D g) {
g.fillOval(x,y,10,10);
}
}
public class Paddle {
private
int x = 400;
int y = 520;
int width = 100;
int height = 6;
int speed = 6;
int dirL = 0;
int dirR = 0;
public
void move() {
x -= speed*dirL;
x += speed*dirR;
}
void stop() {
if (x <= 0)
x = 0;
if (x + width >= 800)
x = 800 - width;
}
int getX() {
return x;
}
int getY() {
return y;
}
int getWidth() {
return width;
}
int getHeight() {
return height;
}
void paint(Graphics2D g) {
g.fillRect(x,y,width,height);
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
dirL = 0;
else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
dirR = 0;
else {
dirL = 0;
dirR = 0;
}
}
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
dirL = 1;
break;
case KeyEvent.VK_RIGHT:
dirR = 1;
break;
}
}
}
public class Brick {
private
int x;
int y;
int width;
int height;
boolean alive;
boolean inX = false,inY = false;
public
void setUpBrick(int px, int py, int w, int h, boolean al) {
x = px;
y = py;
width = w;
height = h;
alive = al;
}
void setAlive(boolean alive) {
this.alive = alive;
}
void paint(Graphics2D g) {
if (alive)
g.fillRect(x,y,width,height);
}
boolean collision(int bx, int by) {
if (alive) {
if (bx + 10 >= x && bx <= x + width && by + 10 >= y && by <= y + height) {
setAlive(false);
return true;
} else return false;
}
else return false;
}
void inAreaX(int bx) {
if (bx + 10 >= x && bx <= x + width) {
System.out.println("inAreaX");
inX = true;
} else {
inX = false;
}
}
void inAreaY(int by) {
if (by + 10 >= y && by <= y + height) {
System.out.println("inAreaY");
inY = true;
} else {
inY = false;
}
}
boolean isInAreaX () {
if (inX)
return true;
else return false;
}
boolean isInAreaY () {
if (inY)
return true;
else return false;
}
}
Ball ball = new Ball();
Paddle paddle = new Paddle();
Brick[][] brick = new Brick[8][4];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 4; j++) {
brick[i][j].setUpBrick(j * 101, i * 51, 100, 50, true);
}
}
void bounce() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 4; j++) {
brick[i][j].inAreaX(ball.getX());
brick[i][j].inAreaY(ball.getY());
if (brick[i][j].collision(ball.getX(), ball.getY())) {
if (brick[i][j].isInAreaX()) {
ball.setDiry();
} else if (brick[i][j].isInAreaY()) {
ball.setDirx();
}
}
}
}
}
void move() {
ball.bounce(paddle.getX(), paddle.getY(), paddle.getWidth(),paddle.getHeight());
ball.move();
paddle.move();
paddle.stop();
bounce();
}
public Breakout() {
addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
paddle.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
paddle.keyPressed(e);
}
});
setFocusable(true);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.RED);
ball.paint(g2d);
g2d.setColor(Color.BLACK);
paddle.paint(g2d);
g2d.setColor(Color.ORANGE);
for (int i = 0; i < 8; i++)
for (int j = 0; j < 4; j++)
brick[i][j].paint(g2d);
}
public static void main(String[] args) throws InterruptedException {
JFrame window = new JFrame("Tennis");
Breakout game = new Breakout();
window.add(game);
window.setSize(800,600);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
Thread.sleep(10);
}
}
i need to inicialize 2d array of brick, but it says that first for is unexpected token. How to write it? Thank you.
Unless if I have miscounted your opening and closing braces, your for loop is not inside any method, it's directly in your class body. That's why you're getting unexpected token. You will probably want to move it into the Breakout constructor.
In order to create a 2D array in Java, you can create such an array like this:
Object testArray = new Object[10][10];
This array is now a 10*10 array with memory allocated for 100 Object references.
You can create pointers two Objects with a double for-loop:
for (int i = 0; i < testArray.length(); i++) {
for (int j = 0; j < testArray.length; j++) {
testArray[i][j] = Object; //here you input the objects that you want to point to
}
}
Move the logic from setUpBrick to a constructor.
public class Brick {
private int x;
private int y;
private int width;
private int height;
private boolean alive;
private boolean inX = false,inY = false;
public Brick(int px, int py, int w, int h, boolean al) {
x = px;
y = py;
width = w;
height = h;
alive = al;
}
...
}
Then change
brick[i][j].setUpBrick(j * 101, i * 51, 100, 50, true);
to
brick[i][j] = new Brick(j*101, i*51, 100, 50, true);
Also note that access modifiers don't apply to a whole section of your class. In your example,
private
int x;
int y;
int width;
int height;
boolean alive;
boolean inX = false,inY = false;
means that only x is going to be private. The rest of the members will get the default access modifier.
One more tip. A couple of your methods can be simplified.
boolean isInAreaY () {
if (inY)
return true;
else return false;
}
can be written as:
boolean isInAreaY() {
return inY;
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
So my Player extends Mob, which extends Entity. In my Level class I have an arraylist and in the main Game class, I add him.
public Level level;
public Player player;
player = new Player(level, 100, 100, input, JOptionPane.showInputDialog(this, "Username:"));
level.addEntity(player);
The problem comes in when I want to REFERENCE the players X and Y so I can plug those into my simple Slime monster AI!
I always get a NullpointerException here (line 7):
public void tick() {
int xa = 0;
int ya = 0;
if (randomWalkTime == 0) {
int xd = level.player.x - x;
int yd = level.player.y - y;
if (xd * xd + yd * yd < 50 * 50) {
xa = 0;
ya = 0;
if (xd < 0) xa = -1;
if (xd > 0) xa = +1;
if (yd < 0) ya = -1;
if (yd > 0) ya = +1;
}
}
move(xa, ya);
randomWalkTime++;
tickCount++;
}
At the first level.player.x :( No matter how I try to reference it. Through game.player.x or anything else I can think of.
Here is the main question: There is a new "Player" that is from an arraylist in another class. How do I reference his x and y in my (Entites>Mob>) Sprite class?
If the code above isn't enough, here is the rest of the important bits:
Here is the LEVEL class where I have my entity arraylist!
public class Level {
private byte[] tiles;
public int width;
public int height;
public List<Entity> entities = new ArrayList<Entity>();
private String imagePath;
private BufferedImage image;
The Entity class!
public abstract class Entity {
public int x, y;
protected Level level;
public Entity(Level level) {
init(level);
}
public final void init(Level level) {
this.level = level;
}
public abstract void tick();
public abstract void render(Screen screen);
}
The Mob Class:
public abstract class Mob extends Entity {
protected String name;
protected int speed;
protected int numSteps = 0;
protected boolean isMoving;
protected int movingDir = 1;
protected int scale = 1;
public Mob(Level level, String name, int x, int y, int speed) {
super(level);
this.name = name;
this.x = x;
this.y = y;
this.speed = speed;
}
public void move(int xa, int ya) {
if (xa != 0 && ya != 0) {
move(xa, 0);
move(0, ya);
numSteps--;
return;
}
numSteps++;
if (!hasCollided(xa, ya)) {
if (ya < 0)
movingDir = 0;
if (ya > 0)
movingDir = 1;
if (xa < 0)
movingDir = 2;
if (xa > 0)
movingDir = 3;
x += xa * speed;
y += ya * speed;
}
}
public abstract boolean hasCollided(int xa, int ya);
protected boolean isSolidTile(int xa, int ya, int x, int y) {
if (level == null) {
return false;
}
Tile lastTile = level.getTile((this.x + x) >> 3, (this.y + y) >> 3);
Tile newTile = level.getTile((this.x + x + xa) >> 3, (this.y + y + ya) >> 3);
if (!lastTile.equals(newTile) && newTile.isSolid()) {
return true;
}
return false;
}
public String getName() {
return name;
}
}
Here is the main part of my SLIME class!
public class Slime extends Mob{
int xa, ya;
private int colour = Colours.get(-1, 111, 145, 543);
private int randomWalkTime = 0;
private boolean isSwimming;
private int tickCount = 0;
public Slime(Level level, String name, int x, int y, int speed) {
super(level, "Slime", x, y, 1);
x = this.x;
y = this.y;
}
public void tick() {
int xa = 0;
int ya = 0;
if (randomWalkTime == 0) {
int xd = level.player.x - x;
int yd = level.player.y - y;
if (xd * xd + yd * yd < 50 * 50) {
xa = 0;
ya = 0;
if (xd < 0) xa = -1;
if (xd > 0) xa = +1;
if (yd < 0) ya = -1;
if (yd > 0) ya = +1;
}
}
move(xa, ya);
randomWalkTime++;
tickCount++;
}
Since level.player.x gives a NPE, you have two posibilities: eitehr level is null or level.player is null. You have two ways to determine which it is:
Preferrably, use a debugger set a breakpoint at the offending line and set a watch on these two variables.
Add System.out.println() calls to print out the values of these two variables.
I have a chicken image that only moves whenever I press my arrow keys, the image always appear at the lower left corner when I start to run the program. My problem is that how can I make the image appear at the top or anywhere on the screen(except on the lower left) and the image still moves when I press the arrow keys . I'm not really sure but I think this problem is coming from my translate(). Is there something wrong with my calculation? Thanks for sharing your ideas...
Here's the code...
public class Chicken extends Sprite implements ImageObserver
{
private java.awt.Image fishImage;
private final Board board;
private double x;
private double y;
private final double chickenHeight = 1.6;
private final double chickenWidth = 1.8;
private double speed;
private boolean visible;
private double angle;
private double dx_m;
private double dy_m;
private boolean collision = false;
public Chicken(Board board, String name, double x, double y, double speed)
{
super(name);
this.board = board;
this.x = x;
this.y = y;
this.speed = convertToMeterPerSecond(speed);
visible = true;
URL iU = this.getClass().getResource("chicken.jpg");
ImageIcon icon = new ImageIcon(iU);
chickenImage = icon.getImage();
}
public Image getImage()
{
return chickenImage;
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
{
dx_m = -0.5;
}
if (key == KeyEvent.VK_RIGHT)
{
dx_m = 0.5;
}
if (key == KeyEvent.VK_UP)
{
dy_m = 0.5;
}
if (key == KeyEvent.VK_DOWN)
{
dy_m = -0.5;
}
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
{
dx_m = 0;
}
if (key == KeyEvent.VK_RIGHT)
{
dx_m = 0;
}
if (key == KeyEvent.VK_UP)
{
dy_m = 0;
}
if (key == KeyEvent.VK_DOWN)
{
dy_m = 0;
}
}
#Override
public void move(long dt)
{
double right_wall = board.x1_world;
double up_wall = board.y1_world;
double down_wall = 0.0;
double left_wall = 0.0;
x += dx_m;
y += dy_m;
if (x >= right_wall)
{
x = right_wall;
}
if (y > up_wall)
{
y = up_wall;
}
if (x <= left_wall)
{
x = left_wall;
}
if (y < down_wall)
{
y = down_wall;
}
}
#Override
public void render(Graphics2D g2d)
{
AffineTransform t = g2d.getTransform();
final double foot_position_y = chickenHeight;
final double foot_position_x = chickenWidth / 2;
double xx = board.convertToPixelX(x - foot_position_x);
double yy = board.convertToPixelY(y + foot_position_y);
g2d.translate(xx, yy);
// ratio for the actual size of the Image
double x_expected_pixels = chickenHeight * board.meter;
double y_expected_pixels = chickenWidth * board.meter;
double w = ((ToolkitImage) chickenImage).getWidth();
double h = ((ToolkitImage) chickenImage).getHeight();
double x_s = x_expected_pixels / w;
double y_s = y_expected_pixels / h;
g2d.scale(x_s, y_s);
g2d.drawImage(getImage(), (int) x, (int) y, this);
g2d.setTransform(t);
}
#Override
public void moveAt(double distance_x, double distance_y)
{
this.x = (int) distance_x;
this.y = (int) distance_y;
}
public void setAngle(double angle)
{
this.angle = angle;
}
#Override
public RectangleX getBounds()
{
return new RectangleX(x, y, chickenWidth, chickenHeight);
}
#Override
public double getWidth()
{
return WIDTH;
}
#Override
public double getHeight()
{
return HEIGHT;
}
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
return true;
}
}
this is my chicken class
public double meter;
int y1_pixel;
y1_pixel = getHeight();
public int convertToPixelX(double distance)
{
return (int) (distance * meter);
}
public int convertToPixelY(double y_world)
{
return (int) (y1_pixel - (y_world * meter));
}
this is coming from my board class.
Your render method is using the x and y coordinates of the class to determine where to draw the Chicken each time. A simple solution to your problem is to use random values for x and y when you create a Chicken instance.
An alternate solution would be to create another constructor that do not take values for x or y and instead sets them to be default values anywhere between 0 and board.x1_world or board.y1_world, depending on the variable.
public Chicken(Board board, String name, double speed)
{
this( board, name,
(int)( Math.random() * ( board.x1_world - chickenWidth ) ),
(int)( Math.random() * ( board.y1_world - chickenHeight ) ),
speed );
}