Java, Slick, An object that shouldnt move is moving? - java

In my game I'm making, I need NPC's/mobs.
I made a class called peasant (my first mob).
In the main class from which the game is running, I have all the information, as well as calling an object called mob1 from Peasant
I need to make it so that if the player is within 300 pixels of the mob, it starts to move towards it. Ive tried doing this but so far, even if the player is 2000 pixels away, the mob starts moving???
Here is my Peasant class
package Entitys.NPCs;
public class Peasant {
public Peasant(float InitX, float InitY, int MobID){
MobX = InitX;
MobY = InitY;
}
//This class shall be used as an object creator. This will randomly move a graphic around, near to a player
private float MobX;
private float MobY;
private int AmountMoved = 0;
private boolean MoveRight = true;
private boolean MoveLeft;
public boolean PlayerDetected = false;
long timer;
//Used to find the mobs X
public float getX(){
return MobX;
}
//Used to find the mobs Y
public float getY(){
return MobY;
}
//Used to set the mobs X
public void setX(float X){
MobX = X;
}
//Used to set the mobs Y
public void setY(float Y){
MobY = Y;
}
//Used to simply move the mob on its X co-ords
public void moveX(int delta){
MobX += delta*0.1f;
}
//Used to simply move the mob on its Y co-ords
public void moveY(int delta){
MobY += delta*0.1f;
}
public void autoEveryThing(int delta, float playerX, float playerY) {
// If the player has not been spotted the NPC/Mob will move left and
// right by 100 Pixels.
if(MobX-300<playerX){
PlayerDetected=true;
}
if(PlayerDetected=true){
if(MobX>playerX){
MobX-=delta*0.12;
}
}
}
}
And here is the main class:
package Worlds.World1;
import org.lwjgl.input.Mouse;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
import Entitys.NPCs.*;
import Main.SimpleMob;
public class World1A extends BasicGameState{
String mousePosition;
Image world;
Animation player, playerLeft, playerRight;
int[] duration = {200,200};
float playerX;
float playerY;
float WorldX;
float WorldY;
float PlayerVisibleScreenX;
float PlayerVisibleScreenY;
String MovementDirection;
Peasant mob1;
public World1A(int state){
}
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
Image [] WalkingLeft = {new Image("res/Sprites/buckysLeft.png"),new Image("res/Sprites/buckysLeft.png")};
Image [] WalkingRight = {new Image("res/Sprites/buckysRight.png"),new Image("res/Sprites/buckysRight.png")};
playerLeft = new Animation(WalkingLeft, duration, false);
playerRight = new Animation(WalkingRight, duration, false);
player = playerRight;
WorldX = 0;
WorldY = 0;
world= new Image("res/WorldImages/WorldBackGround.png");
mousePosition="null";
MovementDirection = "Not Moved Yet";
mob1= new Peasant(2000, 200, 1);
if(WorldX<=0){
playerX = Math.abs(WorldX);
}else{
playerX=0-WorldX;
}
}
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
player.draw(450, 300);
if(WorldX>0){
world.draw(0, 0);
g.fillOval(0+mob1.getX(), 0+mob1.getY(), 50, 50);
g.fillRect(0, 0+340, 500, 10);
player.draw(-WorldX + 450, 300);
}else{
world.draw(WorldX, WorldY);
g.fillOval(WorldX+mob1.getX(), WorldY+mob1.getY(), 50, 50);
g.fillRect(WorldX, WorldY+340, 500, 10);
g.fillOval(WorldX+mob1.getX(), WorldY+mob1.getY(), 50, 50);
player.draw(450, 300);
}
g.setColor(Color.white);
//All this is co-ords ect, it is for developement help
g.drawString(String.valueOf(mob1.getX()), 50, 200);
g.drawString("World X: "+ String.valueOf(WorldX), 50, 225);
g.drawString("Player X: "+ String.valueOf(playerX), 50, 250);
g.drawString("Player Detetcted?: "+ String.valueOf(mob1.PlayerDetected), 50, 265);
}
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException{
if(WorldX<=0){
playerX = Math.abs(WorldX);
}else{
playerX=0-WorldX;
}
mob1.autoEveryThing(delta, playerX, playerY);
int posX = Mouse.getX();
int posY = Mouse.getY();
mousePosition = "X: " + posX + "\nY: " + posY;
Input input = gc.getInput();
if(input.isKeyDown(Input.KEY_LEFT)){
WorldX += delta * 0.1f;
MovementDirection = "Left";
player = playerLeft;
}else if(input.isKeyDown(Input.KEY_RIGHT)){
WorldX -= delta * 0.1f;
MovementDirection = "Right";
player = playerRight;
}else{
MovementDirection = "Not Moving";
}
}
//DO NOT CHANGE
public int getID(){
return 2;
}
}
The autoEveryThing method in the Peasant class should make it so that if(mobX-300
But when I first run this it starts moving towards the player?
even though (2000-300<0) is false, it still sets the PlayerDetected boolean to true???
Why does this happen?
Thanks
EDIT:
After trying to go through thi and fix it I found somthing strange, even if I take out the whole bit which can change PlayerDetected to true, the mob still moves towards the player. This meens that PlayerDetected is becominbg true somwhere, but I cant figure out where?

if(PlayerDetected=true){
is wrong you should use ==
if(PlayerDetected==true){
or even better
boolean isPlayerDetected;
if (isPlayerDetected)
further consider
double dx = mobX - playerX;
double dy = mobY - playerY;
double distance = Math.sqrt(dx*dx + dy*dy);
if (distance < 300) {
// is within distacne threshold
}

Related

Failed to implement object rotation towards mouse JAVA [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
As title say, just can't do it. Attempted for long time and still fail. (I'm new to java)
My Image or fillRect rotate a little bit but not as it should rotate
Whole code +imgs
*MAIN game class*
package game.main;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
public class game extends Canvas implements Runnable{
private static final long serialVersionUID = -392333887196083915L;
public static final int WIDTH = 640, HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
private Handler handler;
public game(){
handler = new Handler();
new window(WIDTH, HEIGHT,"Game",this);
handler.addObject(new Player(WIDTH/2-32, HEIGHT/2-32, ID.Player, handler));
}
public synchronized void start(){
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop(){
try{
thread.join();
running = false;
}catch(Exception e){
e.printStackTrace();
}
}
// ↓ game loop for update
public void run(){
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
delta--;
}
if(running)
render();
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.print("FPS:" + frames);
frames = 0;
}
}
stop();
}
private void tick(){
handler.tick();
}
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(g);
g.dispose();
bs.show();
}
public static void main(String args[]) {
new game();
}
}
<br>
package game.main;
import java.awt.Graphics;
public abstract class GameObject {
protected float x, y;
protected ID id;
protected float velX, velY;
public GameObject(float x, float y, ID id){
this.x = x;
this.y = y;
this.id = id;
}
public abstract void tick();
public abstract void render(Graphics g);
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
public float getX(){
return x;
}
public float getY(){
return y;
}
public void setId(ID id){
this.id = id;
}
public ID getId(){
return id;
}
public void setVelX(int velX){
this.velX = velX;
}
public void setVelY(int velY){
this.velY = velY;
}
public float getVelX(){
return velX;
}
public float getVelY(){
return velY;
}
}
*GameObject class*
package game.main;
import java.awt.Graphics;
public abstract class GameObject {
protected float x, y;
protected ID id;
protected float velX, velY;
public GameObject(float x, float y, ID id){
this.x = x;
this.y = y;
this.id = id;
}
public abstract void tick();
public abstract void render(Graphics g);
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
public float getX(){
return x;
}
public float getY(){
return y;
}
public void setId(ID id){
this.id = id;
}
public ID getId(){
return id;
}
public void setVelX(int velX){
this.velX = velX;
}
public void setVelY(int velY){
this.velY = velY;
}
public float getVelX(){
return velX;
}
public float getVelY(){
return velY;
}
}
*Handler class*
package game.main;
import java.awt.Graphics;
import java.util.LinkedList;
// render all objects
public class Handler {
LinkedList<GameObject> object = new LinkedList<GameObject>();
public void tick(){
for(int i = 0; i < object.size(); i++){
GameObject tempObject = object.get(i);
tempObject.tick();
}
}
public void render(Graphics g){
for(int i = 0; i <object.size();i++){
GameObject tempObject = object.get(i);
tempObject.render(g);
}
}// handling adding objects
public void addObject(GameObject object){
this.object.add(object);
}
}
*window class*
package game.main;
import java.awt.Canvas;
import java.awt.Dimension;
import javax.swing.JFrame;
public class window extends Canvas{
private static final long serialVersionUID = 3010486623466540351L;
public window(int width, int height, String title, game game){
JFrame frame = new JFrame(title);
frame.setPreferredSize(new Dimension(width, height));
frame.setMaximumSize(new Dimension(width, height));
frame.setMinimumSize(new Dimension(width, height));
// X button
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// ¤ button maximize
frame.setResizable(false);
// window appear in middle of screen instead of top left corner
frame.setLocationRelativeTo(null);
// add game to window
frame.add(game);
frame.setVisible(true);
game.start();
}
}
* ID class*
package game.main;
public enum ID {
Player();
}
ADDED code only to this class
*Player class*
package game.main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
public class Player extends GameObject{
Handler handler;
public Player(int x, int y, ID id, Handler handler) {
super(x, y, id);
this.handler = handler;
}
public void tick() {
}
public void render(Graphics g) {
///////////ADDED//////////////////
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
int mouseX = (int) b.getX();
int mouseY = (int) b.getY();
int centerX = game.WIDTH / 2;
int centerY = game.HEIGHT / 2;
double angle = Math.atan2(centerY - mouseY, centerX - mouseX) - Math.PI / 2;
((Graphics2D)g).rotate(angle, centerX, centerY);
//////////////////////////////
g.setColor(Color.white);
g.fillRect((int)x, (int)y, 32, 32);
}
}
How it now works and how I want it. WHITE COLOR - original/ GREEN - I want it like that
Example 1
Example 2
I looked in this sources:
Get mouse possition (stackoverflow)
Java 2d rotation in direction mouse point (stackoverflow)
Rotating an object to point towards the mouse
The problem is that MouseInfo.getPointerInfo().getLocation(); returns the absolute mouse location. You need the mouse location relative to your game canvas. You can modify the render method in your game class as follows:
Point mouseLocation = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(mouseLocation, this);
handler.render(g, mouseLocation);
This requires you to modify the method signatures of your rendering methods accordingly. This is only one way to pass the mouseLocation from your game canvas to your Player's rendering method.
Use the mouseLocation instead of MouseInfo.getPointerInfo().getLocation(); in your Player's render method.
There are a few more things you have to change to place the player in the center of the canvas and make him rotate around his center:
You should set the size of the game canvas instead of the size of the window(JFrame). Do this by calling setPreferredSize(new Dimension(width, height)); on the game canvas and by calling frame.pack() before frame.setVisible(true). This will ensure that your game canvas has exactly the size specified by WIDTH and HEIGHT.
You could add two fields refx and refy to your GameObject class which describe the reference point of your GameObject (e.g. its center). You could then construct a new Player by calling new Player(WIDTH/2-16, HEIGHT/2-16, 16, 16, ID.Player, handler) where the player's initial position is at (WIDTH/2-16, HEIGHT/2-16) and its reference point is (16,16) - the center of the player when the player is represented by a 32x32 rectangle.
In the Player's render method initialize the center you want to rotate around with int centerX = Math.round(x + refx); int centerY = Math.round(y + refy); where (x,y) is the position of the object you want to rotate and (refx, refy) the point you want to rotate around relative to the object's position (e.g. x = WIDTH/2-16, y = HEIGTH/2-16, refx = 16, refy = 16).

Multiple paint() methods in Java applet?

So I am trying to generate random rectangles that the player must avoid. My collision method was working with a single, randomly generated rectangle. I want to draw 10 or so of these and then I will add a finish line and a timer.
Right now, I understand my problem, but I am not sure how to fix it. The ball/player's movement is executed by changing the x or y coordinates by 10 and then repainting the circle. I currently have the rectangles in the same paint method, so each time the player moves the rectangles are regenerated. I would like them to stay in the same place after the initial random generation. I don't really know how to do this though...
Also, if I can get the rectangles to stay in the same place, will my collision method still work with multiple rectangles? or would I need to revise that as well?
I am just going to post the whole program's code because I'm not sure which parts will need to be revised.
import java.awt.*;
import java.awt.Rectangle;
import java.awt.Shape;
import javafx.scene.shape.*;
import java.awt.event.*;
import java.util.Random;
import java.awt.geom.Area;
import javax.swing.JOptionPane;
import java.applet.Applet;
public class Main extends Applet
implements ActionListener{
boolean end = false;
private Rectangle rectangle;
//creates buttons to move player
private Button run = new Button("Run");
private Button jump = new Button("Jump");
private Button fall = new Button("Fall");
//creates player and obstacles
private Circle player = new Circle(110,110,20);
private makeRect block = new makeRect(150, 120, 30, 10);
//initiates the buttons with actionListener
public void init(){
add(run);
add(jump);
add(fall);
run.addActionListener(this);
jump.addActionListener(this);
fall.addActionListener(this);
}
//draws the player and blocks on the screen
public void paint(Graphics g){
for(int numBlocks = 0; numBlocks<11; numBlocks++){
block.draw(g);}
player.draw(g);
}
//if methods to be control movement
public void actionPerformed(ActionEvent e){
if(e.getSource() instanceof Button){
if(e.getSource() == run)
player.horiz(10);
else if (e.getSource()== jump){
player.vert(-10);
}
else if (e.getSource()== fall){
player.down(10);
}
repaint();
collision();
}
}
public void collision(){
if(player.getBounds().intersects(block.getBounds())){
JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
end = true;
}
}
class Circle{
private final Color theColor = Color.BLUE;
private int radius;
private int x,y;
public Circle(){
x = 110; y = 110;
radius = 20;
}
public Circle(int x0, int y0, int rad){
x = x0; y = y0; radius = rad;
}
public void draw(Graphics g){
g.fillOval(x - radius, y-radius, 2*radius, 2*radius);
g.setColor(theColor);
}
public void horiz(int val){
for(int c = 0; c<val+1; c++){
x++;
repaint();}
}
public void vert(int val){
y += val;
}
public void down(int val){
y += val;
}
public Rectangle getBounds(){
return new Rectangle(x-radius, y-radius, 2*radius, 2*radius);
}
}
class makeRect{
private int Xmax = 250;
private int Xmin = 140;
private int Wmax = 50;
private int Hmax = 25;
private int Wmin = 10;
private int Hmin = 5;
Random rand = new Random();
private int randx;
private int randh;
private int x, y, width, height;
public makeRect(){
x = 150; y = 120;
width = 30; height = 10;
}
public makeRect(int x0, int y0, int w0, int h0){
x = x0; y = y0; width = w0; height = h0;
}
public void draw(Graphics g) {
int randx = rand.nextInt((Xmax-Xmin)+1)+Xmin;
int randh = rand.nextInt((Hmax-Hmin)+1)+Hmin;
int randw = rand.nextInt((Wmax-Wmin)+1)+Wmin;
g.drawRect(randx, 110+randh, randh, randw);
}
public Rectangle getBounds(){
return new Rectangle(randx, 110+randh, 30, 10);
}
}
}
Thanks!
For that you will need to construct 10 rects (consider using array) first upon initialization, with random postition for each. I mean, postition randomization occurs when the rects are constructed, not when it's drawn.
What you have there is a same rectangle drawn 10 times at different places each time the paint() gets called.

360 degree movement example in java

is it possible to simply make 360 degree movement in java(swing) without any game engine? all I have is this attempt:
public class Game extends JPanel implements Runnable {
int x = 300;
int y = 500;
float angle = 30;
Game game;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new Game());
frame.setSize(600, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public Game() {
setSize(600, 600);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.drawRect(0, 0, 600, 600);
g.setColor(Color.CYAN);
g.fillOval(x, y, 10, 10);
g.dispose();
}
#Override
public void run() {
while(true) {
angle += -0.1;
x += Math.sin(angle);
y--;
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException ex) {}
}
}
}
as you can see in following picture, I don't know how to handle movement rotating, this is the output:
image http://screenshot.cz/GOXE3/mvm.jpg
Actually, this is quite possible.
My preferred way is to actually take advantage of the Graphics transform so that you don't have to do any computation, it's all left to the Graphics
By the way:
since you did not create the Graphics object, don't ever dispose it.
override paintComponent() rather than paint()
It's always a good pattern to call super.paintComponent()
Small demo example:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestRotate {
public static class ShapeAndColor {
private final Shape shape;
private final Color color;
public ShapeAndColor(Shape shape, Color color) {
super();
this.shape = shape;
this.color = color;
}
public Shape getShape() {
return shape;
}
public Color getColor() {
return color;
}
}
public static class RotatingShapesPanel extends JComponent {
private List<ShapeAndColor> shapes;
private double rotation = 0.0;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
AffineTransform translate = AffineTransform.getTranslateInstance(-getWidth() / 2, -getHeight() / 2);
AffineTransform rotate = AffineTransform.getRotateInstance(rotation);
AffineTransform t = AffineTransform.getTranslateInstance(getWidth() / 2, getHeight() / 2);
t.concatenate(rotate);
t.concatenate(translate);
g2d.setTransform(t);
AffineTransform scale = AffineTransform.getScaleInstance(getWidth(), getHeight());
for (ShapeAndColor shape : shapes) {
Area area = new Area(shape.getShape());
g2d.setColor(shape.getColor());
area.transform(scale);
g2d.fill(area);
}
}
public void setShapes(List<ShapeAndColor> shapes) {
this.shapes = shapes;
repaint();
}
public double getRotation() {
return rotation;
}
public void setRotation(double rotation) {
this.rotation = rotation;
repaint();
}
}
protected void initUI(final boolean useBorderLayout) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
List<ShapeAndColor> shapes = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10; i++) {
double x = r.nextDouble();
double y = r.nextDouble();
double w = r.nextDouble();
double h = r.nextDouble();
w = Math.min(w, 1 - x) / 2;
h = Math.min(h, 1 - y) / 2;
double a = Math.min(w, h) / 10.0;
RoundRectangle2D.Double shape = new RoundRectangle2D.Double(x, y, w, h, a, a);
Color color = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
shapes.add(new ShapeAndColor(shape, color));
}
final RotatingShapesPanel panel = new RotatingShapesPanel();
panel.setShapes(shapes);
frame.add(panel);
frame.setSize(600, 600);
frame.setVisible(true);
Timer t = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
double rotation = panel.getRotation() + 0.02;
if (rotation > Math.PI * 2) {
rotation -= Math.PI * 2;
}
panel.setRotation(rotation);
}
});
t.setRepeats(true);
t.setDelay(10);
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestRotate().initUI(true);
}
});
}
}
Change a few lines...
int basex = 300; // midpoint of the circle
int basey = 400;
int radius = 100; // radius
int x;
int y;
float angle = 0; // Angles in radians, NOT degrees!
public void run() {
while(true) {
angle += 0.01;
x = (int)(basex + radius*Math.cos(angle));
y = (int)(basey - radius*Math.sin(angle));
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException ex) {}
}
}
Not sure what you were trying to code there, but this is the correct formula for a circular movement.
To calculate the rotation around a point, you need a center point for the rotation (cx, cy), the radius or distance of the point from the center, you need the angle (in radians, not degrees), and you need to use sine and cosine to calculate the offset of the point from the center as it rotates around it.
int cx, cy, radius; // I'll let you determine these
double theta = Math.toRadians(30);
double dtheta = Math.toRadians(-0.1);
double dx = Math.cos(theta) * radius;
double dy = Math.sin(theta) * radius;
int x = (int)(cx + dx);
int y = (int)(cy + dy);
repaint();
theta += dtheta; // step the angle
You program has some problems:
int x = 300;
int y = 500;
You should use a floating point data type like double to store the coordinates. You can cast them to int when you want to draw them. If you store them in int, you'll lose precision.
x += Math.sin(angle);
y--;
This doesn't work, since y is decremented instead of calculated using Math.sin(angle). (us Math.cos for x)
This is your fixed code (unchanged parts are omitted):
double x = 300;
double y = 500;
float angle = 30;
double radius = 10D; // new variable to increase the radius of the drawn circle
Game game;
// main method
// constructor
#Override
public void paint(Graphics g) {
// ... stuff omitted
g.fillOval((int)x, (int)y, 10, 10); // you can cast to int here
g.dispose();
}
#Override
public void run() {
while (true) {
angle -= 0.1; // is the same as `angle += -0.1`
x += radius * Math.cos(angle);
y += radius * Math.sin(angle);
repaint();
// ... try catch block
}
}
This currenlty draw the circle counter-clockwise. If you want to draw it clockwise, then change angle to:
angle += 0.1;

Android game: Moving bitmap leaves blurry trail at ends

I am trying to create a background scrolling for an Android game. Lets say it is a set of images moving at a speed.
To test out few basic elements, I have taken a small, rectangular image and moving it linearly from top to bottom. It moves but I see a small trail, like a rocket going in clouds(haha!). I tried various options in Paint() class to rectify this, but I couldn't.
I will first post a screen shot and then add relevant code.
So, here the vertical line is a single png image:
Now all I am doing is moving this bitmap from a certain (x,y) by increasing y by 5 at a time. It moves, but notice the ends of the image while moving. Sort of a trail, but not a permanent one. I have tried but unable to remove this effect. I tried on Samsung Galaxy S5. I didnot test on any other model.
The code:
The moving vertical image is a Sprite object:
package com.src.*.*;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.Log;
public class Sprite {
private Rect sourceRect; // the rectangle to be drawn from the animation bitmap
private int frameNr; // number of frames in animation
private int currentFrame; // the current frame
private long frameTicker; // the time of the last frame update
private int framePeriod; // milliseconds between each frame (1000/fps)
private int spriteWidth; // the width of the sprite to calculate the cut out rectangle
private int spriteHeight; // the height of the sprite
private int x; // the X coordinate of the object (top left of the image)
private int y; // the Y coordinate of the object (top left of the image)
private Bitmap bitmap;
private float degrees;
private boolean rotate=false;
private Matrix matrix;
private Bitmap reversedBitmap;
private Paint paint;
public Sprite(Bitmap bitmap, int x, int y, int fps, int frameCount) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
currentFrame = 0;
frameNr = frameCount;
spriteWidth = bitmap.getWidth() / frameCount;
spriteHeight = bitmap.getHeight();
sourceRect = new Rect(0, 0, spriteWidth, spriteHeight);
framePeriod = 1000 / fps;
frameTicker = 0l;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG);
paint.setDither(true);
}
public void animate(){
}
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 setReverse(Bitmap reverse){
this.reversedBitmap = reverse;
}
public void rorateSprite(float degrees){
if(degrees == 0){
rotate = false;
}else{
rotate = true;
}
this.degrees = degrees;
}
public void draw(Canvas canvas) {
// where to draw the sprite
Rect destRect = new Rect(getX(), getY(), getX() + spriteWidth, getY() + spriteHeight);
if(rotate){
canvas.drawBitmap(reversedBitmap, sourceRect, destRect, paint);
}else{
canvas.drawBitmap(bitmap, sourceRect, destRect, paint);
}
}
public void update(long gameTime){
if (gameTime > frameTicker + framePeriod) {
frameTicker = gameTime;
//Log.i("INFO", "In if loop" + currentFrame + " framenr:" + frameNr);
// increment the frame
currentFrame++;
if (currentFrame >= frameNr) {
currentFrame = 0;
}
}else{
//Log.i("INFO", "in else" + currentFrame + "");
}
// define the rectangle to cut out sprite
//Log.i("INFO", "sprite width: " + spriteWidth);
this.sourceRect.left = currentFrame * spriteWidth;
this.sourceRect.right = this.sourceRect.left + spriteWidth;
}
}
The bitmap is setup as follows:
wallAnimation = new Sprite(resizedBitmapWall, 0, 0, 30, 1);
wallAnimation.setX(margin);
The onDraw and Update for the sprite is as follows. It works without any exception or error. The only issue in all of this is the image having the blurry/tail effect at the ends. I dont even know the right word for it.
Code for onDraw and Update:
#Override
protected void onDraw(Canvas canvas) {
// fills the canvas with black
canvas.drawColor(Color.WHITE);
wallAnimation.draw(canvas);
paint.setColor(Color.BLACK);
for (int i = 0; i < 6; i++) {
canvas.drawLine(margin+laneWidth*i, 0, margin+laneWidth*i, laneHeight, paint);
}
canvas.drawText("High Score: "+ highScore, 10, 10, paint);
}
public void Update(long gameTime) {
// TODO Auto-generated method stub
if(wallState < laneHeight+laneHeight/6){
wallAnimation.setY(wallState);
//wallState+=laneHeight/80;
wallState+=20;
}else{
wallState = 0;
}
}

Java rectangle collision detection confusion

I have made a simple 2D state change game using Bucky's slick Java tutorials, I modified this game and now want to set collisions on the map so that my player can not go through the house on the map. I think I kind of have a idea of how collisions work:
you make 2 rectangles using the following code:
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
1 for the player and 1 for the obstacle, how would I put this into my code and how would I tell java that the rectangle for the obstacle is different to the player rectangle?
Then after making the 2 rectangles I would set up a if statement saying something like if intersects do this...
Hopefully after this I think it would work. Some more information on the game, it being a state change game it has a few methods, methods like init, render and update (where do I place my rectangles and if statements, in the update method?) also, its a overhead view game kind of like pokemon if that helps. If you require my code please ask, I did not want to put it on now to overcrowd this post.
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;
}
}
This is my Play class, the only other 2 class's I have are the main and the menu, I cant imagine the rectangle methods being made in the main or menu class so the only one left is the Play, but I dont understand how to make 2 different Rectangles (one for the player the other for the house) in the code I have done so far. If you require my main and my menu class please tell me.
Edit 3:
I have tried what you have said and made a Rectanglebase class and put the if sattement you had posted inside there but am getting errors, it is asking me to make a method for getX and getY in my player class also the public in fornt of the constructor also has a error:
public Rectanglebase{}//the public is saying syntax error
I also made a Home and Player class like you had said but am a bit confused on what I need to put in it, I put under the Home class:
return Rectangle(100,100,100,100);
but am getting errors, I am not sure if I did this correct or not.
Also, in the player class for the x,y positions how would I set my float variables from my Play class for my player?
Here is an example of a Game Loop / Game Logic and collision detection via Rectangle2D#intersects(..) method .
It uses JPanel to draw everything on and Rectangle2D is used for Entity class (which is any object needed to be drawn to GamePanel which is our JPanel where everything is drawn).
The updateGame() method is where you will find the collision checking:
private void updateGame() {
if (entities.get(0).intersects(entities.get(1))) {
System.out.println("Intersecting");
}
....
}
You are Player 1 and move with W,A,S,D. When you intersect Player 2, a println() will confirm the intersection.
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);
}
}
if(house.getBounds().contains(player.getX(),player.getY()){//do something}
as long as your house and your player rectangles are defined in different classes, java will be able to tell the difference
create a class first that is a base class for dealing with rectangles:
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
now write classes for the house and player:
public class House extends Rectanglebase{
//getBounds() is inherited, so just write stuff to do with the graphics of the house here
}
when you generate the house in your main code, you can make your own:
House house = new House();
then generate the class for the player in a similar way, then construct in in your main code:
Player player = new Player()
house and player are different variables, this is how java will tell the difference between your house and player

Categories