Few days ago I started to work on a 'simple' 2D game. I tried to do it with 'entity system'. I got class 'GameObject' which extends all other objects like trees, enemies (slimes) and so on. All of these game objects are stored in a arrayList called 'gameObjects'. Then I'm using a for loop to iterate through all objects from a list and calling their basic functions like update() and draw(). Until now everything works even though I'm not 100% sure why. The problem is that for some reason I can't do the same with collisions.
I know this topic was discussed many times here but even though after a many days I can't solve this. Can someone help me please? Also, I apologize for my English.
Game class:
public class Game extends BasicGame
{
public Game()
{
super("Game");
}
public void init(GameContainer gameContainer) throws SlickException
{
World.init();
}
public void update(GameContainer gameContainer, int delta) throws SlickException
{
World.update();
}
public void render(GameContainer gameContainer, Graphics g) throws SlickException
{
World.draw(g);
}
}
GameObject class:
public abstract class GameObject
{
protected void update()
{
}
protected void draw()
{
}
}
Tree class:
public class Tree extends GameObject
{
public float x, y;
private static Image tree;
public Tree(float x, float y)
{
this.x = x;
this.y = y;
tree = Resources.miscSheet.getSprite(2, 0);
}
public void draw()
{
tree.draw(x, y)
}
}
Slime class:
public class Slime extends GameObject
{
public static float x;
public static float y;
private static Animation slimeAnim;
public Slime(int x, int y)
{
this.x = x;
this.y = y;
// My own method for loading animation.
slimeAnim = Sprite.getAnimation(Resources.slimeSheet, 0, 0, 5, 300);
}
public void update()
{
// *Random movement here*
}
public void draw()
{
slimeAnim.draw(x, y);
}
}
World class:
public class World
{
public static List<GameObject> gameObjects = new ArrayList<GameObject>();
public static void init()
{
Tree tree = new Tree(0, 0);
Tree tree2 = new Tree(200, 200);
Slime slime = new Slime(80, 80);
gameObjects.add(tree);
gameObjects.add(tree2);
gameObjects.add(slime);
}
public static void update()
{
for (int i = 0; i < gameObjects.size(); i++)
{
GameObject o = gameObjects.get(i);
o.update();
}
}
public static void draw(Graphics g)
{
g.setBackground(new Color(91, 219, 87));
for (int i = 0; i < gameObjects.size(); i++)
{
GameObject o = gameObjects.get(i);
o.draw();
}
}
}
Main class:
public class Main
{
public static AppGameContainer container;
public static void main(String[] args) throws SlickException
{
container = new AppGameContainer(new Game());
container.setDisplayMode(1024, 600, false);
container.setShowFPS(false);
container.start();
}
}
I deleted all my previous collision attempts and I skipped some other unnecessary things. How can I now please implement collisions for example between trees and slimes?
What I usually do is inheriting from Rectangle on my top objectClass. If your GameObject class inherits from Rectangle you'll have intersects method in every instance which gives you a way to easily detect collision.
class GameObject extends Rectangle{}
The problem will be to do the test between all your objects. It will be quite heavy but still possible.
for (int i = 0; i < gameObjects.size(); i++) {
for (int j = i; j < gameObjects.size(); j++) {
if (gameObjects.get(i-1).intersects(gameObjects.get(j)) {
// I don't know what you want to do here
}
}
}
This way you compare object A to object B only once.
Related
I decided I wanted to experiment with making a game and I like Java, so I started following a tutorial here. I did deviate from the video a few times when I felt it was cleaner while being synonymous with the tutorial's code, but not in any way I thought would affect how the code worked. For example, it made sense to me that there should only ever be one instance of the Renderer, and Object Registry so I made them Singletons.
The code I have so far is supposed to create a window with a black background, and a blue square in the middle of the window representing the player, that much is working. However, it should also be sliding around in response to the wasd keys, and even more slowly drifting in one direction regardless. Instead it's doing nothing.
I spent no less than an hour trying to figure out why it wasn't working. It seems to be ticking just fine and the data looks like it's updating properly, but even though my render methods are also being called, the screen just isn't changing.
This is all the code I have so far, since I'm out of ideas as to the problem. I apologize for listing a whole project.
public class Game implements Runnable {
private final Thread thread;
private boolean running = false;
Game() {
thread = new Thread(this);
}
public static void main(String[] args) {
Game game = new Game();
game.start();
new Player(600,450,0));
}
private void start() {
thread.start();
running = true;
}
#Override
public void run() {
double tps = 10.0;
double nsPerTick = 1000000000 / tps;
double delta = 0;
int frames = 0;
long timer = System.currentTimeMillis();
long lTime = System.nanoTime();
long now;
while (running) {
now = System.nanoTime();
delta += (now - lTime) / nsPerTick;
lTime = now;
while (delta >= 1) {
Registry.getInstance().tick();
delta--;
}
if (running) Renderer.getInstance().run();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
stop();
}
private void stop() {
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
running = false;
}
}
public class Renderer extends Canvas {
private static final Renderer renderer = new Renderer();
private final Window window;
private final BufferStrategy bs;
private final Graphics g;
boolean black = true;
private Renderer() {
window = new Window(1200, 900, "First Game", this);
this.createBufferStrategy(2);
bs = this.getBufferStrategy();
g = bs.getDrawGraphics();
addKeyListener(Controller.getInstance());
}
public static Renderer getInstance() {return renderer;}
public void run() {
g.setColor(Color.BLACK);
//this was to see if even the background would update, it wouldn't
//g.setColor(black ? Color.BLACK : Color.WHITE);
//black = !black;
g.fillRect(0,0,1200, 900);
Registry.getInstance().render();
g.dispose();
bs.show();
}
public Graphics getGraphics() {return g;}
private static class Window extends Canvas {
private Window(int width, int height, String title, Renderer renderer) {
JFrame frame = new JFrame(title);
frame.setPreferredSize(new Dimension(width, height));
frame.setMinimumSize(new Dimension(width, height));
frame.setMaximumSize(new Dimension(width, height));
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(renderer);
frame.setVisible(true);
}
}
}
public class Registry {
private static final Registry reg = new Registry();
private final LinkedList<GameObject> objects = new LinkedList<>();
private Registry() {
}
public static Registry getInstance() { return reg; }
public void tick() { //System.out.println("tick");
objects.forEach(GameObject::tick); }
public void render() { objects.forEach(GameObject::render); }
public void add(GameObject gameObject) { objects.add(gameObject); }
public void remove(GameObject gameObject) { objects.remove(gameObject);}
}
public class Controller extends KeyAdapter {
private static final Controller controller = new Controller();
private final HashMap<Character,Boolean> keyStates = new HashMap<>();
private Controller() {
}
public static Controller getInstance() {
return controller;
}
public void keyPressed(KeyEvent e) {
if (!keyStates.getOrDefault(e.getKeyChar(), true)) System.out.println(e.getKeyChar() + " down");
keyStates.put(e.getKeyChar(),true);
}
public void keyReleased(KeyEvent e) {
keyStates.put(e.getKeyChar(),false);
System.out.println(e.getKeyChar() + " up " + keyStates.size());
}
public boolean isKeyDown(char c) {return keyStates.getOrDefault(c,false);}
}
public abstract class GameObject {
protected Graphics graphics = Renderer.getInstance().getGraphics();
protected final ObjectType type;
protected float x,y,r;
protected GameObject(ObjectType objectType, float x, float y, float r) {
this.type = objectType;
this.x = x;
this.y = y;
this.r = r;
Registry.getInstance().add(this);
}
public abstract void tick();
public abstract void render();
public void destroy() { Registry.getInstance().remove(this); }
public float getX() { return x; }
public void setX(float x) { this.x = x; }
public float getY() { return y; }
public void setY(float y) { this.y = y; }
public float getR() { return r; }
public void setR(float r) { this.r = r; }
}
public class Player extends GameObject {
private final Controller controller;
public Player(float x, float y, float r) {
super(ObjectType.PLAYER, x, y, r);
controller = Controller.getInstance();
}
#Override
public void tick() {
this.x += 1;
if (controller.isKeyDown('w')) x += 2;
if (controller.isKeyDown('a')) y -= 2;
if (controller.isKeyDown('s')) x -= 2;
if (controller.isKeyDown('d')) y += 2;
}
#Override
public void render() {
graphics.setColor(Color.BLUE);
graphics.fillRect((int) (this.x-12),(int) (this.y-12), 24,24);
}
}
The problem lies in your handling of Graphics. There's only ONE active Graphics object you can effectively address.
Refactor your code, so that you pass the current Graphics object via parameter through the target methods (like here: Player.render() should become Player.render(Gpahics g). And get rid of the Gameobject.graphics member variable. That is the culprit.
Adding to that, the best way to do simple rendering is to override the paint(Graphics g) method or the paintComponents(Graphics g), and from outside call repaint() on the JPanel/Canvas. This way the UI instigates drawing itself, takes care of the actual frequency, and draws default components/design too if there is some.
I am trying to create 10 bricks using a LinkedList and rendered them randomly to the screen. Why isn't it working? I have been trying to figure it out for 3 days now please give me the answer. I'd really appreciate it. Thank you.
Game.java
public class Game{
private Controller c;
public void init(){
c = new Controller(this);
}
public void run(){
init();
//gameLoop
}
public void tick(){
c.tick();
}
public void render(){
c.render(g);
}
}
Bricks.java
public class Bricks {
private double x, y;
Game game;
private Image BrickImg;
public Bricks(double x, double y, Game game) {
this.x = x;
this.y = y;
this.game = game;
ImageIcon bricksImg = new ImageIcon("res\\bricks.png");
BrickImg = bricksImg.getImage();
}
public void tick() {
}
public void render(Graphics g) {
g.drawImage(BrickImg, (int)x, (int)y, null);
}
}
Controller.java
public class Controller {
Game game;
private LinkedList<Bricks> b = new LinkedList<Bricks>();
Bricks TempBricks;
Random random = new Random();
public Controller(Game game) {
this.game = game;
for (int i = 0; i < 10; i++) {
addBrick(new Bricks(random.nextInt(500), 50, game));
}
}
public void tick() {
for (int i = 0; i < b.size(); i++) {
TempBricks = b.get(i);
}
TempBricks.tick();
}
public void render(Graphics g) {
for (int i = 0; i < b.size(); i++) {
TempBricks = b.get(i);
}
TempBricks.render(g);
}
public void addBrick(Bricks brick) {
b.add(brick);
}
public void removeBrick(Bricks brick) {
b.remove(brick);
}
}
Sorry, but these methods make no sense:
public void tick() {
for (int i = 0; i < b.size(); i++) {
TempBricks = b.get(i);
}
TempBricks.tick(); // ticks the **last** brick in the list
}
public void render(Graphics g) {
for (int i = 0; i < b.size(); i++) {
TempBricks = b.get(i);
}
TempBricks.render(g); // renders only the **last** brick in the list
}
You iterate through the list but only act on the last one -- crazy. Why not act on the items within the for loop?:
public void tick() {
for (int i = 0; i < b.size(); i++) {
b.get(i).tick(); // ticks **every** brick
}
}
public void render(Graphics g) {
for (int i = 0; i < b.size(); i++) {
b.get(i).render; // renders **every** brick
}
}
Also as cricket aptly suggests: get rid of the TempBricks field as all it is doing is confusing you.
As an aside, you will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Plus, a Brick is a singular object, and the class should be named as such. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
Your question suggests that you're not properly debugging your program, and you will benefit greatly by using your IDE's debugger and stepping through the code, seeing what it's doing. Also debug on paper -- walk through your code logically to see if it makes sense.
You only have one TempBricks.
public class Controller {
Game game;
private LinkedList<Bricks> b = new LinkedList<Bricks>();
Bricks TempBricks; // Remove this
And, as a consequence, you only use that one in your loops.
Here's a general shortcut you can use. A for-each loop.
public void render(Graphics g) {
// renders **every** brick
for (Brick brick : b) {
brick.render(g);
}
}
Also, for removeBrick to work correctly, you must implement equals() and hashcode() in your Brick class
I am trying to make a message based collision system for a game test, where all objects are stored in an ArrayList that is iterated through and all objects are checked against all other objects. If two objects collide a Message is sent to both of them and currently it does a sysout (print) when this happens. My code so far is below, I have included the classes I think are relevant but if another class is involved I can post that as well. (I am using Slick2D and LWJGL)
public class MyGame extends BasicGame {
private ArrayList<GameObject> objects = new ArrayList<GameObject>();
MessageQueue messageQueue = new MessageQueue();
CollisionSystem collisionSystem = new CollisionSystem(objects, messageQueue);
public MyGame() {
super("My Game");
}
public static void main(String[] arguments) {
// Start up the game window
try {
AppGameContainer app = new AppGameContainer(new MyGame());
app.setDisplayMode(500, 400, false);
app.start();
app.setVSync(false);
app.setTargetFrameRate(60);
} catch (SlickException e) {
e.printStackTrace();
}
}
#Override
public void init(GameContainer container) throws SlickException {
Image img = new Image("myimage.png", false, Image.FILTER_NEAREST);
objects.add(new ObjSpriteObject(20, 20, img));
objects.add(new ObjSpriteObject(15, 20, img));
}
#Override
public void update(GameContainer container, int delta) throws SlickException {
collisionSystem.update();
messageQueue.update();
for (GameObject object : objects) {
object.update(container, delta);
}
}
#Override
public void render(GameContainer container, Graphics g) throws SlickException {
g.scale(3, 3);
for (GameObject object : objects) {
object.render(container, g);
}
}
}
MessageQueue
public class MessageQueue {
public ArrayList<Message> messages;
public MessageQueue() {
messages = new ArrayList<Message>();
}
public void update() {
while (messages.iterator().hasNext()) {
Message m = messages.iterator().next();
process(m);
}
}
private void process(Message m) {
switch (m.getType()) {
case 'p':
System.out.println("MESSAGE: " + m.getData());
break;
case 'c':
m.getReciever().processMessage(m);
}
}
}
ObjSpriteObject
public class ObjSpriteObject extends GameObject {
private Image sprite;
protected float vspeed = 0f;
protected float hspeed = 0f;
public boolean hasBB = true;
public ObjSpriteObject(int x, int y, Image sprite) {
super(x, y);
this.sprite = sprite;
this.boundingBox = new BoundingBox(this, x, y, 16, 16);
}
#Override
public void update(GameContainer container, int delta) {
super.update(container, delta);
}
#Override
public void render(GameContainer container, Graphics g) {
sprite.draw(x, y);
g.setColor(Color.red);
g.draw(getBoundingBox());
}
#Override
public void processMessage(Message m) {
if (m.getType() == 'c') {
delete = true;
}
}
}
CollisionSystem
public class CollisionSystem {
private ArrayList<GameObject> objects;
private MessageQueue messageQueue;
public CollisionSystem(ArrayList<GameObject> objects, MessageQueue messageQueue) {
this.objects = objects;
this.messageQueue = messageQueue;
}
public void update() {
// Iterate through each BB with each BB
for (int i = 0; i < objects.size(); i++) {
// If object has bounding box
GameObject ob1 = objects.get(i);
if (ob1.getBoundingBox() != null) {
for (int k = 0; k < objects.size(); k++) {
// If second object has bounding box
GameObject ob2 = objects.get(i);
if (ob2.getBoundingBox() != null) {
// Check both bounding boxes and send messages if they collide
BoundingBox bb1 = objects.get(i).getBoundingBox();
BoundingBox bb2 = objects.get(k).getBoundingBox();
// System.out.println(bb1 + " " + bb2);
if (bb1.collides(bb2) && bb1 != bb2) {
messageQueue.messages.add(new Message(bb1.getParent(), bb2.getParent(), 'p', "Collision!"));
}
}
}
}
}
}
}
When I run this code the game freezes. I feel like it has something to do with it running like a while loop that never exits, but I don't see why it would be doing that if the main game loop is making sure things run on a timer. Why is this code freezing the program?
This is my frog class which is being called by a GUI class.
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
public class Frog implements Runnable {
private int x, y, dx, dy;
private int coordinates[]=new int[2];
private boolean hungry;
private JLabel jLabel;
private ImageIcon image;
private String name;
public Frog() {
}
public Frog(String name, boolean hungry) {
image = new ImageIcon("images/frog.jpeg");
jLabel = new JLabel(image);
setName(name);
setHungry(hungry);
setCoordinates();
}
private void setName(String name) {
this.name=name;
}
public int[] getCoordinates() {
return coordinates;
}
public boolean isHungry() {
return hungry;
}
public void setHungry(boolean hungry) {
this.hungry = hungry;
}
public void display(Graphics paper) {
paper.setColor(Color.black);
paper.drawOval(x, y, dx, dx);
}
public void setCoordinates() {
for(int i = 0; i < 2; i++) {
Random rand = new Random();
int p = rand.nextInt(100);
coordinates[i] = p;
}
setX(coordinates[0]);
setY(coordinates[1]);
}
public void move() {
x = (int)Math.random() * 350;
y = (int)Math.random() * 350;
dx=20;
dx=20;
x += dx;
y += dy;
if (x > 800 || x < 0)
dx=-dx;
if (y > 600 || y < 0)
dy=-dy;
}
public void setDx(int dx) {
this.dx = dx;
}
public void setDy(int dy) {
this.dy = dy;
}
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
public void run() {
while(!hungry) {
move();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I have created this class to move a frog object randomly but when I call the move method nothing is happening. I want the frog on a JPanel to randomly move around the screen. I have another class which uses the frog object.
It is used from a main class containing the following:
public void actionPerformed(ActionEvent event) {
if (event.getSource() == MakePet) {
String petName = namePlace.getText();
frog = new Frog(petName,false);
panel.add(pet);
panel.add(prey);
frog.move();
Thread fro = new Thread(frog);
fro.start();
}
}
public static void main(String[] args) {
GUI demo = new GUI();
demo.setSize(520,720);
demo.createGUI();
demo.show();
}
For an example of timer based animation, have a look at http://www.java2s.com/Code/Java/2D-Graphics-GUI/Timerbasedanimation.htm
Another example of timer based animation, where Swing components are used to draw images on a JPanel was given Jérôme's comment: Randomly moving images on a JPanel
If you require having multiple frogs with their own threads of control, then you will need to handle synchronization. Otherwise I would simply call move from the timer before repainting the panel. And then change move:
public void move() {
if (!hungry) {
return;
}
...
}
Set the timer's interval appropriately based on the framerate you are looking to achieve. The below is based on the answer from the question Jérôme linked to:
Timer t = new Timer(1000 / DESIRED_FRAMERATE, (event) -> {
frogs.forEach(Frog::move);
panel.repaint();
});
Note that this is Java 8 using lambdas.
The above in pre-Java 8:
Timer t = new Timer(1000 / DESIRED_FRAMERATE, new ActionListener() {
public void actionPerformed(ActionEvent event) {
for (Frog frog : frogs) {
frog.move();
}
panel.repaint();
}
});
You should create the Timer in the initialization code of your JFrame or JPanel. If you have a class extending JPanel, you don't need to reference panel when calling repaint if the Timer is inside that class. Also, here I am guessing you have a collection of Frog objects, typically a list, called frogs. If there's only ever one frog, you don't need the loop. Frog's display method needs to be called from the JPanel's paint method, so I am guessing you have a class extending JPanel.
here is the entire code for the classes Ship,Asteroids,BaseShapeClass. Ship Class inherits from the BaseShapeClass for its shape. Asteroid class is the main source code which declares the Graphics2D object,AffineTransform(for identity creation),declares double image buffer...
Code for BaseShapeClass..
package baseshapeclass;
import java.awt.Shape;
public class BaseShapeClass {
private Shape shape;
private double x, y;
private double velX, velY;
private double moveAngle, faceAngle;
private boolean alive;
//accessors and mutators
public Shape getShape(){return shape;}
public void setShape(Shape shape){ this.shape = shape; }
public double getX() { return x; }
public void setX(double x) { this.x = x; }
public void incX(double ix) { this.x += ix; }
public double getY() { return y; }
public void setY(double y) { this.y = y; }
public void incY(double iy) { this.y += iy; }
public double getVelX() { return velX; }
public void setVelX(double velX) { this.velX = velX; }
public void incVelX(double ivX) { this.velX += ivX; }
public double getVelY() { return velY; }
public void setVelY(double velY) { this.velY = velY; }
public void incVelY(double ivY) { this.velY += ivY; }
//MoveAngle refers to the objects angular movement
public double getMoveAngle() { return moveAngle; }
public void setMoveAngle(double mAngle) { this.moveAngle = mAngle; }
public void incMoveAngle(double imAngle) { this.moveAngle += imAngle; }
//FaceAngle refers to the objects face/heads angular movement
public double getFaceAngle() { return faceAngle; }
public void setFaceAngle(double fAngle) { this.faceAngle = fAngle; }
public void incFaceAngle(double ifAngle) { this.faceAngle += ifAngle; }
public boolean isAlive() { return alive; }
public void setAlive(boolean alive) { this.alive = alive; }
//default constructor everything will be set to original state
//when update is called everything will start to move
BaseShapeClass(){
setShape(null);
setAlive(false);
//all of them are set to '0' representing their initial position,
//which will be called during the update() Event of the graphics objects
setX(0.0);
setY(0.0);
setVelX(0.0);
setVelY(0.0);
setMoveAngle(0.0);
setFaceAngle(0.0);
}
}
Code for Ship class...
package baseshapeclass;
import java.awt.Rectangle;
import java.awt.Polygon;
public class Ship extends BaseShapeClass {
//ships shape along the x and y cordinates
private final int[] shipx = {-6,3,0,3,6,0};
private final int[] shipy = {6,7,7,7,6,-7};
public Rectangle getBounds(){
Rectangle r = new Rectangle((int)getX()-6, (int)getY()-6, 12, 12);
return r;
}
Ship(){
setShape(new Polygon(shipx, shipy, shipx.length));
setAlive(true);
}
}
Code for Asteroid(Main source code)...
package baseshapeclass;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public abstract class Asteroid extends Applet implements Runnable, KeyListener {
BufferedImage backbuffer;
Graphics2D g2d;
Ship ship = new Ship();
boolean showBounds= true;
AffineTransform identity = new AffineTransform();
#Override public void init(){
backbuffer = new BufferedImage(640,480,BufferedImage.TYPE_INT_RGB);
g2d = backbuffer.createGraphics();
ship.setX(320);
ship.setY(240);
addKeyListener(this);
}
#Override public void update(Graphics g){
g2d.setTransform(identity);
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, getSize().width, getSize().height);
g2d.setColor(Color.WHITE);
g2d.drawString("Ship: "+Math.round(ship.getX())+" , "+Math.round(ship.getY()),2, 150);
g2d.drawString("Face Angle: "+Math.toRadians(ship.getFaceAngle()),5, 30);
g2d.drawString("Move Angle: "+Math.toRadians(ship.getMoveAngle())+90,5,50);
drawShip();
paint(g);
}
public void drawShip(){
g2d.setTransform(identity);
g2d.translate(ship.getX(),ship.getY());
g2d.rotate(Math.toRadians(ship.getFaceAngle()));
g2d.setColor(Color.ORANGE);
g2d.fill(ship.getShape());
}
}
I hope you guys get a better idea with all the code in place. Just wanted to know on the part of Ship class why are the ships x and y cordinates such as under:
public class ship extends BaseShapeClass{
private int[] shipx = {-6,3,0,3,6,0};
private int[] shipy = {6,7,7,7,6,-7};
}
I cant follow on how those values will make upto a Polygon??
Ship(){
setShape(new Polygon(shipx,shipy,shipx.length));
setAlive(true);
}
You can see that the two arrays you are confused about go into the initialization of a Polygon. These two arrays, taken as a pair, give the x and y coordinates of each point in the Polygon.
This post is in answer to your comment in Kronion's answer; I was going to post it as a comment, but there is too much to say and I wanted to show you some code, which is not as legible in the comments.
As Kronion said, the Polygon class does indeed accept an array of X coordinates, and an array of Y coordinates. The reason for this is that the X and Y coordinate are stored at the same position in both arrays. So if int index = 0, then that X,Y coordinate pair would be xArray[index] and yArray[index].
If that doesn't make any sense, examine the Polygon class source code. For example, you'll see this happening in the contains method, here:
for (int i = 0; i < npoints; lastx = curx, lasty = cury, i++) {
curx = xpoints[i];
cury = ypoints[i];
// remainder of loop
}
So in short, they are assigned in this manner because the X and Y are paired by their index positions.
Hope that helps.