the method is:
Robot robot = new Robot();
Color inputColor = new Color();
Rectangle rectangle = new Rectangle(0, 0, 1365, 770);
BufferedImage image = robot.createScreenCapture(rectangle);
for(int x = 0; x < rectangle.getWidth(); x++)
{
for (int y = 0; y < rectangle.getHeight(); y++)
{
if (image.getRGB(x, y) == inputColor.getRGB())
{
robot.mouseMove(x, y);
break;
}
}
}
return;
}
i want to call that method with a value for Color have it search the screenshot for that color and return with the (x, y) values for the pixel if it is found can that happen or can a method have only one input and the output has to be the same?
You can do something like this:
Point methodName(Color color) {
Point p = new Point();
// logic for finding point
return p; // or perhaps return null if color not found
}
You could also just return a two-element int[] instead of a point.
Method input and output could be different, but it can't return more than one type(or)value, either x or y. If you want to return both x,y. You may need to return as array (or) You can have a POJO class something like below, set x,y to instance of that class and return.
Dimension
{
int x;
int y;
setter..
getter..
}
You can return the java.awt.Point with the x and y values or use an int array if that would be fine.
Related
So I can load a 2D map using tiles using a text file, which is great and all. However, one issue I have met with this method is that I can't add objects/actors to my map since the file is a 2D grid. (The game is similar to games like zelda and pokemon.) I've tried creating an object layer so I can overlap images, but it doesn't seem to work for me. To give an example of what I want, have objects such as trees to be solid and on top of the background grass.
I am also looking for better methods to creating these tile based maps if you want to pitch some ideas to me.
**Note: I am about beginner/intermediate at Java.
Here is my constructor for the GameState class that calls the Map.
public GameState(Game game) {
super(game);
player = new Player(game, 0, 0, 64, 64);
map = new Map(game, "res/saves/save1.txt");
}
Here is the Map class (which works) that also calls the object (2nd) layer.
private int width, height;
public static int spawnX, spawnY;
private int[][] mapTiles;
MapObjects mapObjects;
Game game;
public Map(Game game, String path) {
this.game = game;
mapObjects = new MapObjects(game, "res/saves/save1_obj.txt", width, height);
loadMap(path);
}
private void loadMap(String path) {
String file = Utils.loadFileAsString(path);
//Token is which number it is out of the total
String[] tokens = file.split("\\s+");
//Sets what is what
width = Utils.parseInt(tokens[0]);
height = Utils.parseInt(tokens[1]);
spawnX = Utils.parseInt(tokens[2]);
spawnY = Utils.parseInt(tokens[3]);
mapTiles = new int[width][height];
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
// (x+y*width) : calculates the nth token (+4) : The 4 prior tokens before the graph
mapTiles[x][y] = Utils.parseInt(tokens[(x + y *width) + 4]);
}
}
}
public void render(Graphics g) {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
//Only renders what is seen.
getMapTile(x, y).render(g, (int)(x*Tile.TILE_WIDTH-game.getCamera().getxOffset()), (int)(y*Tile.TILE_HEIGHT-game.getCamera().getyOffset()));
}
}
}
public void tick() {
}
//Gets the specific tile at specific coordinates.
private Tile getMapTile(int x, int y) {
Tile t = Tile.tiles[mapTiles[x][y]];
if(t == null) {
return Tile.grassTile;
}
return t;
}
And lastly, the object layer that doesn't work. It does not give an error, just the overlapping objects aren't visible. I've made sure to load the object layer before the Map layer, but that doesn't seem to be the issue.
private int width, height;
private int[][] objTiles;
Game game;
public MapObjects(Game game, String path, int width, int height) {
this.game = game;
loadObjects(path, width, height);
}
public void loadObjects(String path, int width, int height) {
this.width = width;
this.height = height;
String file = Utils.loadFileAsString(path);
String[] tokens = file.split("\\s+");
objTiles = new int[width][height];
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
objTiles[x][y] = Utils.parseInt(tokens[(x + y *width)]);
}
}
}
public void render(Graphics g) {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
//Only renders what is seen.
getObjTile(x, y).render(g, (int)(x*Tile.TILE_WIDTH-game.getCamera().getxOffset()), (int)(y*Tile.TILE_HEIGHT-game.getCamera().getyOffset()));
}
}
}
public void tick() {
}
//Gets the specific object tile at specific coordinates.
private Tile getObjTile(int x, int y) {
Tile t = Tile.tiles[objTiles[x][y]];
if(t == null) {
return Tile.nothingTile;
}
return t;
}
We may need a bit more info from you.
Do you use a different "container/component" to draw map tiles than you do for your objects? Because if you render objects first then they will disappear as soon as you render the map. You should draw the map first, and then do objects like so:
public Map(Game game, String path) {
this.game = game;
//swapped the order of the lines below so the map loads first:
loadMap(path);
mapObjects = new MapObjects(game, "res/saves/save1_obj.txt", width, height);
}
From what you have said then this does not work either, however if you use the same component to draw your map and objects then one will always override the other, and something will always be missing. To fix this you need to crease two separate panes, one for the map, and a transparent one that sits on top of the map that you can use to render your objects.
See this illustration as an example:
You basically need to add a new transparent "content plane" similar to the way that glass pane shown above.
EDIT: to clarify, one of my requirements is to use a single array.
I am having trouble storing multiple variables to a single element in an array. We are creating a really simple program to mimic Microsoft Paint. One of the requirements is to store each element I draw in to an array so that the 'paint' method repaints the drawings each time the windows is minimized and then redisplayed. Here are the requirements
We are to assume a max size for the array is 20.
Each element should include 5 variables:
char shape (l for line, r for rectangle, c for circle)
Start x value
Start y value
width (rectangle), or ending x (line), or radius (circle)
height (rectangle), or ending y (line), or radius (circle)
Here is my code for the array class:
class storeDraws {
final int MAXSIZE = 20;
static int S[];
static int n; //number of draws user makes
static char shape;
static double px, py, w, h;
storeDraws () {
S = new int [MAXSIZE];
n = 0;
shape = 'l';
px = 0;
py = 0;
w = 0;
h = 0;
}
}
I have read a few places that I can input the array as (using the mouseReleased(MouseEvent e) method:
storeDraws[] input = new storeDraws{value, value, value, value, value};
But I don't think that would work for what I am trying to do with the 'paint' method to redraw the shapes. I thought I could somehow pass it using the standard format of S[n] = (char, double, double, double, double), but I get warning that this is illegal.
Edit 8:30 am
I got this part working. In my class here is my code now.
class storeDraws {
static char shape;
static int px, py, w, h;
storeDraws () {
shape = 'l';
px = 0;
py = 0;
w = 0;
h = 0;
}
}
I then declared this in the DrawPanel class:
private storeDraws[] store = new storeDraws[20];
private int n = 0;
And mouseReleased method of DrawPanel:
public void mouseReleased(MouseEvent e) {
if (drawShape == "line") {
store[n].shape = 'l';
store[n].px = p1.x;
store[n].py = p1.y;
store[n].w = p3.x;
store[n].h = p3.y;
n++;
}
And paint:
public void paint(Graphics g) {
for (int i = 0; i < n; i++) {
if (store[i].shape == 'l')
g.drawLine(store[n].px, store[n].py, store[n].w, store[n].h);
But if I draw 6 lines it only repaints the last line.
I think you need to separate some of the functionality you want. You can have a class for each of the elements and then store instances of the class in an array of DrawingElement objects.
So you'd do something like this:
DrawingElement[] drawing = new DrawingElement[20];
DrawingElement circle = new DrawingElement('c', 10, 10, 10, 10);
DrawingElement rect = new DrawingElement('r', 20, 10, 10, 10);
drawing[0] = circle;
drawing[1] = rect;
Note: If you need to be able to get the number of objects in the array (variable n in your code) you may want to use some implementation of
a Linked List (which has a size() method) and do some check when adding elements to make sure you don't add past the max of 20.
Example with LinkedList:
LinkedList<DrawingElement> drawing = new LinkedList<DrawingElement>();
DrawingElement circle = new DrawingElement('c', 10, 10, 10, 10);
DrawingElement rect = new DrawingElement('r', 20, 10, 10, 10);
drawing.add(circle);
drawing.add(rect);
int n = drawing.size(); //will be 2
The Drawing Element Class:
public class DrawingElement
{
char shape;
double px, py, w, h;
public DrawingElement(char shape, double px, double py, double w, double h)
{
this.shape = shape;
this.px = px;
this.py = py;
this.w = w;
this.h = h;
}
//Add getters and setters (accessors and mutators) for class variables
}
I think you should use collection for this purpose.Create array, store values
then add each array object in collection(list).
you can use arraylist instead of array. this will help you to store different variable.
If there is need of using only array you can use object array
Sample Code
object a[]= {'a',10,10.2,10.3,10.4,10.5}
Please refer ArrayList
In your case it would be better to use Java Collection(ArrayList) rather than Array.
First point, We cannot store different types of variables values into an Array.
An array is a container object that holds a fixed number of values of a single type.
Here you are trying to store multiple type of variables into integer array.
see this link:
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
To overcome this drawback, We have Collection API introduced with JDK1.5
Refer this link:
http://docs.oracle.com/javase/tutorial/collections/index.html
I'm trying to write a method for my game that will take an image, the hex value for the old color, and the hex value for the new color and then convert all pixels of the old color to the new color. Right now, the method paints the entire image the new color, as if the if statement is not working at all. This the method:
private void convertColors(BufferedImage img, int oldColor, int newColor)
{
Graphics g = img.getGraphics();
g.setColor(new Color(newColor));
Color old = new Color(oldColor);
for(int x = 0; x < img.getWidth(); x++)
{
for(int y = 0; y < img.getHeight(); y++)
{
Color tmp = new Color(img.getRGB(x, y));
if(tmp.equals(old));
{
System.out.println("Temp=" + tmp.toString() + "Old=" + old.toString() + "New=" + g.getColor().toString());
g.fillRect(x, y, 1, 1);
}
}
}
g.dispose();
}
*The hex for oldColor is 0xFFFFFF (white) and for newColor is 0xFF0000 (red).
Using the println method I get these kind of results:
Temp=java.awt.Color[r=0,g=0,b=0]Old=java.awt.Color[r=255,g=255,b=255]New=java.awt.Color[r=255,g=0,b=0]
Temp=java.awt.Color[r=255,g=255,b=255]Old=java.awt.Color[r=255,g=255,b=255]New=java.awt.Color[r=255,g=0,b=0]
The scond line looks correct, the temp color and the old are the same, but that is obviously not the case with the first. I have also tried creating a new BufferedImage and copy over the pixels but that leaves the same result... Does the equals method not work as I think it does or does this entire method just not work and there's a better way to do this? Thanks for you help in advance.
Just remove the ; after if(tmp.equals(old)).
Otherwise you compare the colors and do nothing after the comparsion and always choose the new color.
Besides that you need to reorganize your code a little bit to make it slightly more efficient:
Graphics g = img.getGraphics();
g.setColor(new Color(newColor));
for(int x = 0; x < img.getWidth(); x++) {
for(int y = 0; y < img.getHeight(); y++) {
if(img.getRGB(x, y) == oldColor) {//check if pixel color matches old color
g.fillRect(x, y, 1, 1);//fill the pixel with the right color
}
}
}
g.dispose();
Just because i was interested in the topic: relying on image filters you could do all that via:
class ColorSwapFilter extends RGBImageFilter {
int newColor, oldColor;
public ColorSwapFilter(int newColor, int oldColor) {
canFilterIndexColorModel = true;
this.newColor = newColor;
this.oldColor = oldColor;
}
#Override
public int filterRGB(int x, int y, int rgb) {
return rgb == oldColor ? newColor : oldColor;
}
}
which should be called via
BufferedImage img;//your image
ColorSwapFilter filter = new ColorSwapFilter(...,...);//your colors to be swapped.
ImageProducer producer = img.getSource();
producer = new FilteredImageSource(producer, filter);
Image im = Toolkit.getDefaultToolkit().createImage(producer);
You have a semicolon direct after your if statement if(tmp.equals(old));
This esentially tells Java that your if statement has only one command associated with it, and that command is a single semicolon, effectively meaning "do nothing". If you remove it, it will restore the condition on the block of code beneath it, which right now is just running every time regardless of the condition.
I got it to work; this is the working convertColors method:
private BufferedImage convertColors(BufferedImage img, int oldColor, int newColor)
{
int [] pixels = new int [img.getWidth() * img.getHeight()];
img.getRGB(0, 0, img.getWidth(), img.getHeight(), pixels, 0, img.getWidth());
Color old = new Color(oldColor);
Color newC = new Color(newColor);
for(int x = 0; x < img.getWidth(); x++)
{
for(int y = 0; y < img.getHeight(); y++)
{
Color tmp = new Color(pixels[x + y * img.getWidth()]);
if(tmp.equals(old))
{
pixels[x + y * img.getWidth()] = newC.getRGB();
}
}
}
img.setRGB(0, 0, img.getWidth(), img.getHeight(), pixels, 0, img.getWidth());
return newImg;
}
I don't know if this is a simple problem or not, but I just can't see what the problem is. I've gotten three reports now from my app in Google Play of an IndexOutOfBoundsException at points.get(++i).
public GameThread(SurfaceHolder sHolder, Context context, Handler handler)
{
points = new ArrayList<Float>();
running = true;
mSurfaceHolder = sHolder;
}
protected void doDraw(Canvas canvas)
{
Paint p = new Paint();
p.setStyle(Paint.Style.FILL);
p.setColor(Color.WHITE);
for (int i = 0; i < points.size(); i++)
{
float x = points.get(i);
float y = points.get(++i);
canvas.drawPoint(x, y, p);
}
}
public boolean onTouchEvent(MotionEvent event)
{
float x = event.getX();
float y = event.getY();
points.add(x);
points.add(y);
return true;
}
The index it fails at is trying to access the location equal to its size (Actually one error says
java.lang.IndexOutOfBoundsException: Invalid index 2205, size is 2206 which makes NO sense at all to me), and its size varies.
The only way I can see this happening is if for some reason only one object is added to points, and I don't know why that would happen. onTouchEvent isn't running in its own thread, is it?
The problem is at this line:
float y = points.get(++i);
When i = points.size()-1, you preincrement, and then you invoke points.get(++i);. At this point, i = points.size() => Out of bounds. Just remove the ++ to fix it.
EDIT
Alternatively, you can try this approach:
List<Point> points = ...
protected void doDraw(Canvas canvas) {
Paint p = new Paint();
p.setStyle(Paint.Style.FILL);
p.setColor(Color.WHITE);
for (Point p : points) {
canvas.drawPoint(p.x, p.y, p);
}
}
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
points.add(new Point(x, y));
return true;
}
I would make the for-loop safe from problems like this by letting the for loop construct handle all of the i variable logic, don't try to do it yourself.
for (int i = 0; i+1 < points.size(); i+=2){
float x = points.get(i);
float y = points.get(i+1);
canvas.drawPoint(x, y, p);
}
Your problem is in your for-loop. While the first access would work, the second access is not guaranteed to be correct. If you only have one object, then the loop can't work because you are trying to access the next element in the array, which doesn't exist.
Try
for (int i = 0; i < points.size()-1; i++)
suppose your array length is 10
float y = points.get(++i);
you can replace this statement by
^^^
float y = points.get(i+1);
You are increasing value of Y here as well as here
for (int i = 0; i < points.size(); i++)
^^^
In for loop it checks i<points.size() means it 9 or less than 9
when you reach to 9
and in for loop you are accessing points.get(++i);
it will access points.get(10) <-------- here you gets exception
and your arry is 0-9 then is no element at 10
Use your Point object correctly, like:
Point point = new Point();
point.x = value;
point.y = value;
to print, or use.. its just point.x and point.y still. (in case of android.graphics.Point;)
If you want to store several points, you can use for example ArrayList
ArrayList<Point> pointArray = new ArrayList<Point>();
pointArray.add(new Point(event.getX(), event.getY()));
To loop it throught:
for(Point p : pointArray){
// do something with p.x and p.y
}
I have this code:
{
Robot robot = new Robot();
Color inputColor = new Color();
Rectangle rectangle = new Rectangle(0, 0, 1365, 770);
BufferedImage image = robot.createScreenCapture(rectangle);
for(int x = 0; x < rectangle.getWidth(); x++)
{
for (int y = 0; y < rectangle.getHeight(); y++)
{
if (image.getRGB(x, y) == inputColor.getRGB())
{
return 1;
break;
}
}
}
}
it is supposed to, and does, take a screenshot and find in it a pixel specified by the inputColor. However the program requirements have changed, and now it needs to find a string of pixels 5 long that match a given string. Is there an easy way to specify this with the existing code, or will I need to change it? I mean, can I keep the existing code and define inputColor as a string with the values of the 5 pixels, or do I need to change the whole algorithm?
I think something like this would work. Not the best efficiency, but its a bone to chew.
int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth())) {
for (int i = 0; i < pixels.length; i++) {
if (Array.equals(search, Array.copyOfRange(pixels, i, i + search.length)) {
//found it
}
}
search would be an array of integers(your colors).