Initial commit
This commit is contained in:
123
Java/Raycaster/src/main/java/de/craftix/raycaster/Player.java
Normal file
123
Java/Raycaster/src/main/java/de/craftix/raycaster/Player.java
Normal file
@@ -0,0 +1,123 @@
|
||||
package de.craftix.raycaster;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
public class Player implements KeyListener {
|
||||
|
||||
public static Point2D position;
|
||||
public static double rotation;
|
||||
|
||||
public static boolean updateRays = false;
|
||||
|
||||
private float horizontal = 0;
|
||||
private float vertical = 0;
|
||||
|
||||
public Player() {
|
||||
position = new Point(150, 150);
|
||||
rotation = 0;
|
||||
Raycaster.Raycast(position, rotation);
|
||||
}
|
||||
|
||||
public void Update() {
|
||||
Point2D orig = new Point2D.Double(position.getX(), position.getY());
|
||||
int speed = 20;
|
||||
if (horizontal > 0) {
|
||||
double x = Math.sin(rotation) * Window.deltaTime * speed;
|
||||
double y = -Math.cos(rotation) * Window.deltaTime * speed;
|
||||
position = new Point2D.Double(position.getX() + x, position.getY() + y);
|
||||
updateRays = true;
|
||||
} else if (horizontal < 0) {
|
||||
double x = Math.sin(rotation) * Window.deltaTime * speed;
|
||||
double y = -Math.cos(rotation) * Window.deltaTime * speed;
|
||||
position = new Point2D.Double(position.getX() - x, position.getY() - y);
|
||||
updateRays = true;
|
||||
}
|
||||
|
||||
if (vertical > 0) {
|
||||
rotation -= Window.deltaTime * 1.5;
|
||||
updateRays = true;
|
||||
} else if (vertical < 0) {
|
||||
rotation += Window.deltaTime * 1.5;
|
||||
updateRays = true;
|
||||
}
|
||||
|
||||
int intersection = Window.map.getRGB((int) position.getX(), (int) position.getY());
|
||||
if (intersection != 0) {
|
||||
updateRays = true;
|
||||
position = orig;
|
||||
}
|
||||
|
||||
if (updateRays) {
|
||||
Raycaster.Raycast(position, rotation);
|
||||
updateRays = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(Graphics2D g) {
|
||||
Raycaster.RenderRays(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_W)
|
||||
horizontal = 1;
|
||||
if (e.getKeyCode() == KeyEvent.VK_S)
|
||||
horizontal = -1;
|
||||
|
||||
if (e.getKeyCode() == KeyEvent.VK_A)
|
||||
vertical = 1;
|
||||
if (e.getKeyCode() == KeyEvent.VK_D)
|
||||
vertical = -1;
|
||||
|
||||
if (e.getKeyCode() == KeyEvent.VK_UP) {
|
||||
Raycaster.resolution++;
|
||||
Raycaster.resolution = clamp(Raycaster.resolution, 5, Window.frame.getWidth());
|
||||
updateRays = true;
|
||||
}
|
||||
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
|
||||
Raycaster.resolution--;
|
||||
Raycaster.resolution = clamp(Raycaster.resolution, 5, Window.frame.getWidth());
|
||||
updateRays = true;
|
||||
}
|
||||
|
||||
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
|
||||
Raycaster.fov++;
|
||||
Raycaster.fov = clamp(Raycaster.fov, 30, 120);
|
||||
updateRays = true;
|
||||
}
|
||||
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
|
||||
Raycaster.fov--;
|
||||
Raycaster.fov = clamp(Raycaster.fov, 30, 120);
|
||||
updateRays = true;
|
||||
}
|
||||
|
||||
if (e.getKeyCode() == KeyEvent.VK_SPACE)
|
||||
Raycaster.curate = !Raycaster.curate;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_W)
|
||||
horizontal = 0;
|
||||
if (e.getKeyCode() == KeyEvent.VK_S)
|
||||
horizontal = 0;
|
||||
|
||||
if (e.getKeyCode() == KeyEvent.VK_A)
|
||||
vertical = 0;
|
||||
if (e.getKeyCode() == KeyEvent.VK_D)
|
||||
vertical = 0;
|
||||
}
|
||||
|
||||
private int clamp(int value, int min, int max) {
|
||||
return Math.max(Math.min(value, max), min);
|
||||
}
|
||||
}
|
||||
849
Java/Raycaster/src/main/java/de/craftix/raycaster/Polygon2D.java
Normal file
849
Java/Raycaster/src/main/java/de/craftix/raycaster/Polygon2D.java
Normal file
@@ -0,0 +1,849 @@
|
||||
package de.craftix.raycaster;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Polygon2D implements Shape, Cloneable, Serializable {
|
||||
|
||||
/**
|
||||
* The total number of points. The value of <code>npoints</code>
|
||||
* represents the number of valid points in this <code>Polygon</code>.
|
||||
*
|
||||
*/
|
||||
public int npoints;
|
||||
|
||||
/**
|
||||
* The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
|
||||
* number of points in this <code>Polygon2D</code>.
|
||||
*
|
||||
*/
|
||||
public float[] xpoints;
|
||||
|
||||
/**
|
||||
* The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
|
||||
* number of points in this <code>Polygon2D</code>.
|
||||
*
|
||||
*/
|
||||
public float[] ypoints;
|
||||
|
||||
/**
|
||||
* Bounds of the Polygon2D.
|
||||
* @see #getBounds()
|
||||
*/
|
||||
protected Rectangle2D bounds;
|
||||
|
||||
private GeneralPath path;
|
||||
private GeneralPath closedPath;
|
||||
|
||||
/**
|
||||
* Creates an empty Polygon2D.
|
||||
*/
|
||||
public Polygon2D() {
|
||||
xpoints = new float[4];
|
||||
ypoints = new float[4];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a <code>Polygon2D</code> from the specified
|
||||
* Rectangle2D.
|
||||
* @param rec the Rectangle2D
|
||||
* @exception NullPointerException rec is <code>null</code>.
|
||||
*/
|
||||
public Polygon2D(Rectangle2D rec) {
|
||||
if (rec == null) {
|
||||
throw new IndexOutOfBoundsException("null Rectangle");
|
||||
}
|
||||
npoints = 4;
|
||||
xpoints = new float[4];
|
||||
ypoints = new float[4];
|
||||
xpoints[0] = (float)rec.getMinX();
|
||||
ypoints[0] = (float)rec.getMinY();
|
||||
xpoints[1] = (float)rec.getMaxX();
|
||||
ypoints[1] = (float)rec.getMinY();
|
||||
xpoints[2] = (float)rec.getMaxX();
|
||||
ypoints[2] = (float)rec.getMaxY();
|
||||
xpoints[3] = (float)rec.getMinX();
|
||||
ypoints[3] = (float)rec.getMaxY();
|
||||
calculatePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a <code>Polygon2D</code> from the specified
|
||||
* Polygon.
|
||||
* @param pol the Polygon
|
||||
* @exception NullPointerException pol is <code>null</code>.
|
||||
*/
|
||||
public Polygon2D(Polygon pol) {
|
||||
if (pol == null) {
|
||||
throw new IndexOutOfBoundsException("null Polygon");
|
||||
}
|
||||
this.npoints = pol.npoints;
|
||||
this.xpoints = new float[pol.npoints];
|
||||
this.ypoints = new float[pol.npoints];
|
||||
for (int i = 0; i < pol.npoints; i++) {
|
||||
xpoints[i] = pol.xpoints[i];
|
||||
ypoints[i] = pol.ypoints[i];
|
||||
}
|
||||
calculatePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a <code>Polygon2D</code> from the specified
|
||||
* parameters.
|
||||
* @param xpoints an array of <i>x</i> coordinates
|
||||
* @param ypoints an array of <i>y</i> coordinates
|
||||
* @param npoints the total number of points in the <code>Polygon2D</code>
|
||||
* @exception NegativeArraySizeException if the value of
|
||||
* <code>npoints</code> is negative.
|
||||
* @exception IndexOutOfBoundsException if <code>npoints</code> is
|
||||
* greater than the length of <code>xpoints</code>
|
||||
* or the length of <code>ypoints</code>.
|
||||
* @exception NullPointerException if <code>xpoints</code> or
|
||||
* <code>ypoints</code> is <code>null</code>.
|
||||
*/
|
||||
public Polygon2D(float[] xpoints, float[] ypoints, int npoints) {
|
||||
if (npoints > xpoints.length || npoints > ypoints.length) {
|
||||
throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
|
||||
}
|
||||
this.npoints = npoints;
|
||||
this.xpoints = new float[npoints];
|
||||
this.ypoints = new float[npoints];
|
||||
System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
|
||||
System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
|
||||
calculatePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a <code>Polygon2D</code> from the specified
|
||||
* parameters.
|
||||
* @param xpoints an array of <i>x</i> coordinates
|
||||
* @param ypoints an array of <i>y</i> coordinates
|
||||
* @param npoints the total number of points in the <code>Polygon2D</code>
|
||||
* @exception NegativeArraySizeException if the value of
|
||||
* <code>npoints</code> is negative.
|
||||
* @exception IndexOutOfBoundsException if <code>npoints</code> is
|
||||
* greater than the length of <code>xpoints</code>
|
||||
* or the length of <code>ypoints</code>.
|
||||
* @exception NullPointerException if <code>xpoints</code> or
|
||||
* <code>ypoints</code> is <code>null</code>.
|
||||
*/
|
||||
public Polygon2D(int[] xpoints, int[] ypoints, int npoints) {
|
||||
if (npoints > xpoints.length || npoints > ypoints.length) {
|
||||
throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
|
||||
}
|
||||
this.npoints = npoints;
|
||||
this.xpoints = new float[npoints];
|
||||
this.ypoints = new float[npoints];
|
||||
for (int i = 0; i < npoints; i++) {
|
||||
this.xpoints[i] = xpoints[i];
|
||||
this.ypoints[i] = ypoints[i];
|
||||
}
|
||||
calculatePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this <code>Polygon</code> object to an empty polygon.
|
||||
*/
|
||||
public void reset() {
|
||||
npoints = 0;
|
||||
bounds = null;
|
||||
path = new GeneralPath();
|
||||
closedPath = null;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
Polygon2D pol = new Polygon2D();
|
||||
for (int i = 0; i < npoints; i++) {
|
||||
pol.addPoint(xpoints[i], ypoints[i]);
|
||||
}
|
||||
return pol;
|
||||
}
|
||||
|
||||
private void calculatePath() {
|
||||
path = new GeneralPath();
|
||||
path.moveTo(xpoints[0], ypoints[0]);
|
||||
for (int i = 1; i < npoints; i++) {
|
||||
path.lineTo(xpoints[i], ypoints[i]);
|
||||
}
|
||||
bounds = path.getBounds2D();
|
||||
closedPath = null;
|
||||
}
|
||||
|
||||
private void updatePath(float x, float y) {
|
||||
closedPath = null;
|
||||
if (path == null) {
|
||||
path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
|
||||
path.moveTo(x, y);
|
||||
bounds = new Rectangle2D.Float(x, y, 0, 0);
|
||||
} else {
|
||||
path.lineTo(x, y);
|
||||
float _xmax = (float)bounds.getMaxX();
|
||||
float _ymax = (float)bounds.getMaxY();
|
||||
float _xmin = (float)bounds.getMinX();
|
||||
float _ymin = (float)bounds.getMinY();
|
||||
if (x < _xmin) _xmin = x;
|
||||
else if (x > _xmax) _xmax = x;
|
||||
if (y < _ymin) _ymin = y;
|
||||
else if (y > _ymax) _ymax = y;
|
||||
bounds = new Rectangle2D.Float(_xmin, _ymin, _xmax - _xmin, _ymax - _ymin);
|
||||
}
|
||||
}
|
||||
|
||||
/* get the associated {@link Polyline2D}.
|
||||
*/
|
||||
public Polyline2D getPolyline2D() {
|
||||
|
||||
Polyline2D pol = new Polyline2D( xpoints, ypoints, npoints );
|
||||
|
||||
pol.addPoint( xpoints[0], ypoints[0]);
|
||||
|
||||
return pol;
|
||||
}
|
||||
|
||||
public Polygon getPolygon() {
|
||||
int[] _xpoints = new int[npoints];
|
||||
int[] _ypoints = new int[npoints];
|
||||
for (int i = 0; i < npoints; i++) {
|
||||
_xpoints[i] = (int)xpoints[i]; // todo maybe rounding is better ?
|
||||
_ypoints[i] = (int)ypoints[i];
|
||||
}
|
||||
|
||||
return new Polygon(_xpoints, _ypoints, npoints);
|
||||
}
|
||||
|
||||
public void addPoint(Point2D p) {
|
||||
addPoint((float)p.getX(), (float)p.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the specified coordinates to this <code>Polygon2D</code>.
|
||||
* @param x the specified x coordinate
|
||||
* @param y the specified y coordinate
|
||||
*/
|
||||
public void addPoint(float x, float y) {
|
||||
if (npoints == xpoints.length) {
|
||||
float[] tmp;
|
||||
|
||||
tmp = new float[npoints * 2];
|
||||
System.arraycopy(xpoints, 0, tmp, 0, npoints);
|
||||
xpoints = tmp;
|
||||
|
||||
tmp = new float[npoints * 2];
|
||||
System.arraycopy(ypoints, 0, tmp, 0, npoints);
|
||||
ypoints = tmp;
|
||||
}
|
||||
xpoints[npoints] = x;
|
||||
ypoints[npoints] = y;
|
||||
npoints++;
|
||||
updatePath(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the specified {@link Point} is inside this
|
||||
* <code>Polygon</code>.
|
||||
* @param p the specified <code>Point</code> to be tested
|
||||
* @return <code>true</code> if the <code>Polygon</code> contains the
|
||||
* <code>Point</code>; <code>false</code> otherwise.
|
||||
* @see #contains(double, double)
|
||||
*/
|
||||
public boolean contains(Point p) {
|
||||
return contains(p.x, p.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the specified coordinates are inside this
|
||||
* <code>Polygon</code>.
|
||||
* <p>
|
||||
* @param x the specified x coordinate to be tested
|
||||
* @param y the specified y coordinate to be tested
|
||||
* @return <code>true</code> if this <code>Polygon</code> contains
|
||||
* the specified coordinates, (<i>x</i>, <i>y</i>);
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean contains(int x, int y) {
|
||||
return contains((double) x, (double) y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the high precision bounding box of the {@link Shape}.
|
||||
* @return a {@link Rectangle2D} that precisely
|
||||
* bounds the <code>Shape</code>.
|
||||
*/
|
||||
public Rectangle2D getBounds2D() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public Rectangle getBounds() {
|
||||
if (bounds == null) return null;
|
||||
else return bounds.getBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified coordinates are inside this
|
||||
* <code>Polygon</code>. For the definition of
|
||||
* <i>insideness</i>, see the class comments of {@link Shape}.
|
||||
* @param x the specified x coordinate
|
||||
* @param y the specified y coordinate
|
||||
* @return <code>true</code> if the <code>Polygon</code> contains the
|
||||
* specified coordinates; <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean contains(double x, double y) {
|
||||
if (npoints <= 2 || !bounds.contains(x, y)) {
|
||||
return false;
|
||||
}
|
||||
updateComputingPath();
|
||||
|
||||
return closedPath.contains(x, y);
|
||||
}
|
||||
|
||||
private void updateComputingPath() {
|
||||
if (npoints >= 1) {
|
||||
if (closedPath == null) {
|
||||
closedPath = (GeneralPath)path.clone();
|
||||
closedPath.closePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a specified {@link Point2D} is inside the boundary of this
|
||||
* <code>Polygon</code>.
|
||||
* @param p a specified <code>Point2D</code>
|
||||
* @return <code>true</code> if this <code>Polygon</code> contains the
|
||||
* specified <code>Point2D</code>; <code>false</code>
|
||||
* otherwise.
|
||||
* @see #contains(double, double)
|
||||
*/
|
||||
public boolean contains(Point2D p) {
|
||||
return contains(p.getX(), p.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the interior of this <code>Polygon</code> intersects the
|
||||
* interior of a specified set of rectangular coordinates.
|
||||
* @param x the x coordinate of the specified rectangular
|
||||
* shape's top-left corner
|
||||
* @param y the y coordinate of the specified rectangular
|
||||
* shape's top-left corner
|
||||
* @param w the width of the specified rectangular shape
|
||||
* @param h the height of the specified rectangular shape
|
||||
* @return <code>true</code> if the interior of this
|
||||
* <code>Polygon</code> and the interior of the
|
||||
* specified set of rectangular
|
||||
* coordinates intersect each other;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean intersects(double x, double y, double w, double h) {
|
||||
if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
|
||||
return false;
|
||||
}
|
||||
updateComputingPath();
|
||||
return closedPath.intersects(x, y, w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the interior of this <code>Polygon</code> intersects the
|
||||
* interior of a specified <code>Rectangle2D</code>.
|
||||
* @param r a specified <code>Rectangle2D</code>
|
||||
* @return <code>true</code> if this <code>Polygon</code> and the
|
||||
* interior of the specified <code>Rectangle2D</code>
|
||||
* intersect each other; <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean intersects(Rectangle2D r) {
|
||||
return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the interior of this <code>Polygon</code> entirely
|
||||
* contains the specified set of rectangular coordinates.
|
||||
* @param x the x coordinate of the top-left corner of the
|
||||
* specified set of rectangular coordinates
|
||||
* @param y the y coordinate of the top-left corner of the
|
||||
* specified set of rectangular coordinates
|
||||
* @param w the width of the set of rectangular coordinates
|
||||
* @param h the height of the set of rectangular coordinates
|
||||
* @return <code>true</code> if this <code>Polygon</code> entirely
|
||||
* contains the specified set of rectangular
|
||||
* coordinates; <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean contains(double x, double y, double w, double h) {
|
||||
if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
updateComputingPath();
|
||||
return closedPath.contains(x, y, w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the interior of this <code>Polygon</code> entirely
|
||||
* contains the specified <code>Rectangle2D</code>.
|
||||
* @param r the specified <code>Rectangle2D</code>
|
||||
* @return <code>true</code> if this <code>Polygon</code> entirely
|
||||
* contains the specified <code>Rectangle2D</code>;
|
||||
* <code>false</code> otherwise.
|
||||
* @see #contains(double, double, double, double)
|
||||
*/
|
||||
public boolean contains(Rectangle2D r) {
|
||||
return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator object that iterates along the boundary of this
|
||||
* <code>Polygon</code> and provides access to the geometry
|
||||
* of the outline of this <code>Polygon</code>. An optional
|
||||
* {@link AffineTransform} can be specified so that the coordinates
|
||||
* returned in the iteration are transformed accordingly.
|
||||
* @param at an optional <code>AffineTransform</code> to be applied to the
|
||||
* coordinates as they are returned in the iteration, or
|
||||
* <code>null</code> if untransformed coordinates are desired
|
||||
* @return a {@link PathIterator} object that provides access to the
|
||||
* geometry of this <code>Polygon</code>.
|
||||
*/
|
||||
public PathIterator getPathIterator(AffineTransform at) {
|
||||
updateComputingPath();
|
||||
if (closedPath == null) return null;
|
||||
else return closedPath.getPathIterator(at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator object that iterates along the boundary of
|
||||
* the <code>Polygon2D</code> and provides access to the geometry of the
|
||||
* outline of the <code>Shape</code>. Only SEG_MOVETO, SEG_LINETO, and
|
||||
* SEG_CLOSE point types are returned by the iterator.
|
||||
* Since polygons are already flat, the <code>flatness</code> parameter
|
||||
* is ignored.
|
||||
* @param at an optional <code>AffineTransform</code> to be applied to the
|
||||
* coordinates as they are returned in the iteration, or
|
||||
* <code>null</code> if untransformed coordinates are desired
|
||||
* @param flatness the maximum amount that the control points
|
||||
* for a given curve can vary from colinear before a subdivided
|
||||
* curve is replaced by a straight line connecting the
|
||||
* endpoints. Since polygons are already flat the
|
||||
* <code>flatness</code> parameter is ignored.
|
||||
* @return a <code>PathIterator</code> object that provides access to the
|
||||
* <code>Shape</code> object's geometry.
|
||||
*/
|
||||
public PathIterator getPathIterator(AffineTransform at, double flatness) {
|
||||
return getPathIterator(at);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This class has the same behavior than {@link Polygon2D}, except that
|
||||
* the figure is not closed.
|
||||
*
|
||||
* @version $Id: Polyline2D.java 594018 2007-11-12 04:17:41Z cam $
|
||||
*/
|
||||
class Polyline2D implements Shape, Cloneable, Serializable {
|
||||
|
||||
private static final float ASSUME_ZERO = 0.001f;
|
||||
|
||||
/**
|
||||
* The total number of points. The value of <code>npoints</code>
|
||||
* represents the number of points in this <code>Polyline2D</code>.
|
||||
*
|
||||
*/
|
||||
public int npoints;
|
||||
|
||||
/**
|
||||
* The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
|
||||
* number of points in this <code>Polyline2D</code>.
|
||||
*
|
||||
*/
|
||||
public float[] xpoints;
|
||||
|
||||
/**
|
||||
* The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
|
||||
* number of points in this <code>Polyline2D</code>.
|
||||
*
|
||||
*/
|
||||
public float[] ypoints;
|
||||
|
||||
/**
|
||||
* Bounds of the Polyline2D.
|
||||
* @see #getBounds()
|
||||
*/
|
||||
protected Rectangle2D bounds;
|
||||
|
||||
private GeneralPath path;
|
||||
private GeneralPath closedPath;
|
||||
|
||||
/**
|
||||
* Creates an empty Polyline2D.
|
||||
*/
|
||||
public Polyline2D() {
|
||||
xpoints = new float[4];
|
||||
ypoints = new float[4];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a <code>Polyline2D</code> from the specified
|
||||
* parameters.
|
||||
* @param xpoints an array of <i>x</i> coordinates
|
||||
* @param ypoints an array of <i>y</i> coordinates
|
||||
* @param npoints the total number of points in the
|
||||
* <code>Polyline2D</code>
|
||||
* @exception NegativeArraySizeException if the value of
|
||||
* <code>npoints</code> is negative.
|
||||
* @exception IndexOutOfBoundsException if <code>npoints</code> is
|
||||
* greater than the length of <code>xpoints</code>
|
||||
* or the length of <code>ypoints</code>.
|
||||
* @exception NullPointerException if <code>xpoints</code> or
|
||||
* <code>ypoints</code> is <code>null</code>.
|
||||
*/
|
||||
public Polyline2D(float[] xpoints, float[] ypoints, int npoints) {
|
||||
if (npoints > xpoints.length || npoints > ypoints.length) {
|
||||
throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
|
||||
}
|
||||
this.npoints = npoints;
|
||||
this.xpoints = new float[npoints+1]; // make space for one more to close the polyline
|
||||
this.ypoints = new float[npoints+1]; // make space for one more to close the polyline
|
||||
System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
|
||||
System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
|
||||
calculatePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a <code>Polyline2D</code> from the specified
|
||||
* parameters.
|
||||
* @param xpoints an array of <i>x</i> coordinates
|
||||
* @param ypoints an array of <i>y</i> coordinates
|
||||
* @param npoints the total number of points in the <code>Polyline2D</code>
|
||||
* @exception NegativeArraySizeException if the value of
|
||||
* <code>npoints</code> is negative.
|
||||
* @exception IndexOutOfBoundsException if <code>npoints</code> is
|
||||
* greater than the length of <code>xpoints</code>
|
||||
* or the length of <code>ypoints</code>.
|
||||
* @exception NullPointerException if <code>xpoints</code> or
|
||||
* <code>ypoints</code> is <code>null</code>.
|
||||
*/
|
||||
public Polyline2D(int[] xpoints, int[] ypoints, int npoints) {
|
||||
if (npoints > xpoints.length || npoints > ypoints.length) {
|
||||
throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
|
||||
}
|
||||
this.npoints = npoints;
|
||||
this.xpoints = new float[npoints];
|
||||
this.ypoints = new float[npoints];
|
||||
for (int i = 0; i < npoints; i++) {
|
||||
this.xpoints[i] = xpoints[i];
|
||||
this.ypoints[i] = ypoints[i];
|
||||
}
|
||||
calculatePath();
|
||||
}
|
||||
|
||||
public Polyline2D(Line2D line) {
|
||||
npoints = 2;
|
||||
xpoints = new float[2];
|
||||
ypoints = new float[2];
|
||||
xpoints[0] = (float)line.getX1();
|
||||
xpoints[1] = (float)line.getX2();
|
||||
ypoints[0] = (float)line.getY1();
|
||||
ypoints[1] = (float)line.getY2();
|
||||
calculatePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this <code>Polyline2D</code> object to an empty polygon.
|
||||
* The coordinate arrays and the data in them are left untouched
|
||||
* but the number of points is reset to zero to mark the old
|
||||
* vertex data as invalid and to start accumulating new vertex
|
||||
* data at the beginning.
|
||||
* All internally-cached data relating to the old vertices
|
||||
* are discarded.
|
||||
* Note that since the coordinate arrays from before the reset
|
||||
* are reused, creating a new empty <code>Polyline2D</code> might
|
||||
* be more memory efficient than resetting the current one if
|
||||
* the number of vertices in the new polyline data is significantly
|
||||
* smaller than the number of vertices in the data from before the
|
||||
* reset.
|
||||
*/
|
||||
public void reset() {
|
||||
npoints = 0;
|
||||
bounds = null;
|
||||
path = new GeneralPath();
|
||||
closedPath = null;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
Polyline2D pol = new Polyline2D();
|
||||
for (int i = 0; i < npoints; i++) {
|
||||
pol.addPoint(xpoints[i], ypoints[i]);
|
||||
}
|
||||
return pol;
|
||||
}
|
||||
|
||||
private void calculatePath() {
|
||||
path = new GeneralPath();
|
||||
path.moveTo(xpoints[0], ypoints[0]);
|
||||
for (int i = 1; i < npoints; i++) {
|
||||
path.lineTo(xpoints[i], ypoints[i]);
|
||||
}
|
||||
bounds = path.getBounds2D();
|
||||
closedPath = null;
|
||||
}
|
||||
|
||||
private void updatePath(float x, float y) {
|
||||
closedPath = null;
|
||||
if (path == null) {
|
||||
path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
|
||||
path.moveTo(x, y);
|
||||
bounds = new Rectangle2D.Float(x, y, 0, 0);
|
||||
} else {
|
||||
path.lineTo(x, y);
|
||||
float _xmax = (float)bounds.getMaxX();
|
||||
float _ymax = (float)bounds.getMaxY();
|
||||
float _xmin = (float)bounds.getMinX();
|
||||
float _ymin = (float)bounds.getMinY();
|
||||
if (x < _xmin) _xmin = x;
|
||||
else if (x > _xmax) _xmax = x;
|
||||
if (y < _ymin) _ymin = y;
|
||||
else if (y > _ymax) _ymax = y;
|
||||
bounds = new Rectangle2D.Float(_xmin, _ymin, _xmax - _xmin, _ymax - _ymin);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPoint(Point2D p) {
|
||||
addPoint((float)p.getX(), (float)p.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the specified coordinates to this <code>Polyline2D</code>.
|
||||
* <p>
|
||||
* If an operation that calculates the bounding box of this
|
||||
* <code>Polyline2D</code> has already been performed, such as
|
||||
* <code>getBounds</code> or <code>contains</code>, then this
|
||||
* method updates the bounding box.
|
||||
* @param x the specified x coordinate
|
||||
* @param y the specified y coordinate
|
||||
* @see java.awt.Polygon#getBounds
|
||||
* @see java.awt.Polygon#contains(double,double)
|
||||
*/
|
||||
public void addPoint(float x, float y) {
|
||||
if (npoints == xpoints.length) {
|
||||
float[] tmp;
|
||||
|
||||
tmp = new float[npoints * 2];
|
||||
System.arraycopy(xpoints, 0, tmp, 0, npoints);
|
||||
xpoints = tmp;
|
||||
|
||||
tmp = new float[npoints * 2];
|
||||
System.arraycopy(ypoints, 0, tmp, 0, npoints);
|
||||
ypoints = tmp;
|
||||
}
|
||||
xpoints[npoints] = x;
|
||||
ypoints[npoints] = y;
|
||||
npoints++;
|
||||
updatePath(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bounding box of this <code>Polyline2D</code>.
|
||||
* The bounding box is the smallest {@link Rectangle} whose
|
||||
* sides are parallel to the x and y axes of the
|
||||
* coordinate space, and can completely contain the <code>Polyline2D</code>.
|
||||
* @return a <code>Rectangle</code> that defines the bounds of this
|
||||
* <code>Polyline2D</code>.
|
||||
*/
|
||||
public Rectangle getBounds() {
|
||||
if (bounds == null) return null;
|
||||
else return bounds.getBounds();
|
||||
}
|
||||
|
||||
private void updateComputingPath() {
|
||||
if (npoints >= 1) {
|
||||
if (closedPath == null) {
|
||||
closedPath = (GeneralPath)path.clone();
|
||||
closedPath.closePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the specified {@link Point} is inside this
|
||||
* <code>Polyline2D</code>.
|
||||
* This method is required to implement the Shape interface,
|
||||
* but in the case of Line2D objects it always returns false since a line contains no area.
|
||||
*/
|
||||
public boolean contains(Point p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified coordinates are inside this
|
||||
* <code>Polyline2D</code>.
|
||||
* This method is required to implement the Shape interface,
|
||||
* but in the case of Line2D objects it always returns false since a line contains no area.
|
||||
*/
|
||||
public boolean contains(double x, double y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the specified coordinates are inside this
|
||||
* <code>Polyline2D</code>.
|
||||
* This method is required to implement the Shape interface,
|
||||
* but in the case of Line2D objects it always returns false since a line contains no area.
|
||||
*/
|
||||
public boolean contains(int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the high precision bounding box of the {@link Shape}.
|
||||
* @return a {@link Rectangle2D} that precisely
|
||||
* bounds the <code>Shape</code>.
|
||||
*/
|
||||
public Rectangle2D getBounds2D() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a specified {@link Point2D} is inside the boundary of this
|
||||
* <code>Polyline2D</code>.
|
||||
* This method is required to implement the Shape interface,
|
||||
* but in the case of Line2D objects it always returns false since a line contains no area.
|
||||
*/
|
||||
public boolean contains(Point2D p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the interior of this <code>Polygon</code> intersects the
|
||||
* interior of a specified set of rectangular coordinates.
|
||||
* @param x the x coordinate of the specified rectangular
|
||||
* shape's top-left corner
|
||||
* @param y the y coordinate of the specified rectangular
|
||||
* shape's top-left corner
|
||||
* @param w the width of the specified rectangular shape
|
||||
* @param h the height of the specified rectangular shape
|
||||
* @return <code>true</code> if the interior of this
|
||||
* <code>Polygon</code> and the interior of the
|
||||
* specified set of rectangular
|
||||
* coordinates intersect each other;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean intersects(double x, double y, double w, double h) {
|
||||
if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
|
||||
return false;
|
||||
}
|
||||
updateComputingPath();
|
||||
return closedPath.intersects(x, y, w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the interior of this <code>Polygon</code> intersects the
|
||||
* interior of a specified <code>Rectangle2D</code>.
|
||||
* @param r a specified <code>Rectangle2D</code>
|
||||
* @return <code>true</code> if this <code>Polygon</code> and the
|
||||
* interior of the specified <code>Rectangle2D</code>
|
||||
* intersect each other; <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean intersects(Rectangle2D r) {
|
||||
return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the interior of this <code>Polyline2D</code> entirely
|
||||
* contains the specified set of rectangular coordinates.
|
||||
* This method is required to implement the Shape interface,
|
||||
* but in the case of Line2D objects it always returns false since a line contains no area.
|
||||
*/
|
||||
public boolean contains(double x, double y, double w, double h) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the interior of this <code>Polyline2D</code> entirely
|
||||
* contains the specified <code>Rectangle2D</code>.
|
||||
* This method is required to implement the Shape interface,
|
||||
* but in the case of Line2D objects it always returns false since a line contains no area.
|
||||
*/
|
||||
public boolean contains(Rectangle2D r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator object that iterates along the boundary of this
|
||||
* <code>Polygon</code> and provides access to the geometry
|
||||
* of the outline of this <code>Polygon</code>. An optional
|
||||
* {@link AffineTransform} can be specified so that the coordinates
|
||||
* returned in the iteration are transformed accordingly.
|
||||
* @param at an optional <code>AffineTransform</code> to be applied to the
|
||||
* coordinates as they are returned in the iteration, or
|
||||
* <code>null</code> if untransformed coordinates are desired
|
||||
* @return a {@link PathIterator} object that provides access to the
|
||||
* geometry of this <code>Polygon</code>.
|
||||
*/
|
||||
public PathIterator getPathIterator(AffineTransform at) {
|
||||
if (path == null) return null;
|
||||
else return path.getPathIterator(at);
|
||||
}
|
||||
|
||||
/* get the associated {@link Polygon2D}.
|
||||
* This method take care that may be the last point can
|
||||
* be equal to the first. In that case it must not be included in the Polygon,
|
||||
* as polygons declare their first point only once.
|
||||
*/
|
||||
public Polygon2D getPolygon2D() {
|
||||
Polygon2D pol = new Polygon2D();
|
||||
for (int i = 0; i < npoints - 1; i++) {
|
||||
pol.addPoint(xpoints[i], ypoints[i]);
|
||||
}
|
||||
Point2D.Double p0 =
|
||||
new Point2D.Double(xpoints[0], ypoints[0]);
|
||||
Point2D.Double p1 =
|
||||
new Point2D.Double(xpoints[npoints-1], ypoints[npoints-1]);
|
||||
|
||||
if (p0.distance(p1) > ASSUME_ZERO)
|
||||
pol.addPoint(xpoints[npoints-1], ypoints[npoints-1]);
|
||||
|
||||
return pol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator object that iterates along the boundary of
|
||||
* the <code>Shape</code> and provides access to the geometry of the
|
||||
* outline of the <code>Shape</code>. Only SEG_MOVETO and SEG_LINETO, point types
|
||||
* are returned by the iterator.
|
||||
* Since polylines are already flat, the <code>flatness</code> parameter
|
||||
* is ignored.
|
||||
* @param at an optional <code>AffineTransform</code> to be applied to the
|
||||
* coordinates as they are returned in the iteration, or
|
||||
* <code>null</code> if untransformed coordinates are desired
|
||||
* @param flatness the maximum amount that the control points
|
||||
* for a given curve can vary from colinear before a subdivided
|
||||
* curve is replaced by a straight line connecting the
|
||||
* endpoints. Since polygons are already flat the
|
||||
* <code>flatness</code> parameter is ignored.
|
||||
* @return a <code>PathIterator</code> object that provides access to the
|
||||
* <code>Shape</code> object's geometry.
|
||||
*/
|
||||
public PathIterator getPathIterator(AffineTransform at, double flatness) {
|
||||
return path.getPathIterator(at);
|
||||
}
|
||||
}
|
||||
204
Java/Raycaster/src/main/java/de/craftix/raycaster/Raycaster.java
Normal file
204
Java/Raycaster/src/main/java/de/craftix/raycaster/Raycaster.java
Normal file
@@ -0,0 +1,204 @@
|
||||
package de.craftix.raycaster;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.Serializable;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class Raycaster {
|
||||
private static TreeMap<Float, Double> rays = new TreeMap<>();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new Window("Raycaster", new Dimension(1280, 720));
|
||||
}
|
||||
|
||||
public static int fov = 60;
|
||||
public static int resolution = 500;
|
||||
public static boolean curate = false;
|
||||
|
||||
private static boolean updating = false;
|
||||
|
||||
private static BufferedImage scaledMap;
|
||||
private static final int scalingFactor = 10;
|
||||
|
||||
public static void Raycast(Point2D origin, double direction) {
|
||||
updating = true;
|
||||
if (scaledMap == null) {
|
||||
scaledMap = Resizer.BICUBIC.resize(Window.map, Window.map.getWidth() * scalingFactor, Window.map.getHeight() * scalingFactor);
|
||||
}
|
||||
|
||||
rays = new TreeMap<>();
|
||||
double step = fov / (double) resolution;
|
||||
double halfFOV = fov / 2d;
|
||||
|
||||
for (double i = -halfFOV; i < halfFOV; i += step) {
|
||||
double relativeDirection = Math.toRadians(i);
|
||||
double dx = Math.sin(direction + relativeDirection) / scalingFactor;
|
||||
double dy = -Math.cos(direction + relativeDirection) / scalingFactor;
|
||||
Point2D ray = SingleRay(origin.getX(), origin.getY(), dx, dy);
|
||||
double dist = origin.distance(ray);
|
||||
rays.put(map((float) (i + halfFOV), 0, fov, 0, Window.frame.getWidth()), dist);
|
||||
}
|
||||
updating = false;
|
||||
}
|
||||
|
||||
public static void RenderRays(Graphics2D g) {
|
||||
if (updating) return;
|
||||
float width = Window.frame.getWidth() / (float) resolution;
|
||||
Float[] xValues = rays.keySet().toArray(new Float[0]);
|
||||
Double[] distValues = rays.values().toArray(new Double[0]);
|
||||
|
||||
for (int i = 0; i < rays.size(); i++) {
|
||||
float x = xValues[i];
|
||||
double dist = distValues[i];
|
||||
double nextDist = i == rays.size() - 1 || !curate ? dist : distValues[i + 1];
|
||||
Shape shape = GenerateScreenObject(x, (float) dist, (float) nextDist, width, i);
|
||||
int brightness = clamp((int)map((float) dist, 100, 0, 0, 255), 0, 255);
|
||||
g.setColor(new Color(brightness, brightness, brightness));
|
||||
g.fill(shape);
|
||||
}
|
||||
}
|
||||
|
||||
private static Point2D SingleRay(double x, double y, double dx, double dy) {
|
||||
boolean intersected = false;
|
||||
while (!intersected) {
|
||||
try {
|
||||
int bit = scaledMap.getRGB((int) (x * scalingFactor), (int) (y * scalingFactor));
|
||||
if (bit == -0x1000000) {
|
||||
x = x + dx;
|
||||
y = y + dy;
|
||||
}else intersected = true;
|
||||
}catch (Exception e) {
|
||||
intersected = true;
|
||||
}
|
||||
}
|
||||
return new Point2D.Double(x, y);
|
||||
}
|
||||
|
||||
private static Shape GenerateScreenObject(float x, float dist, float nextDist, float width, int interrator) {
|
||||
float height = 4000f / dist;
|
||||
float nextHeight = 4000f / nextDist;
|
||||
if (height - nextHeight > 100) nextHeight = height;
|
||||
float middle = Window.frame.getHeight() / 2f;
|
||||
return new Polygon2D(
|
||||
new float[] {
|
||||
x, x, x + width,
|
||||
x, x + width, x + width
|
||||
},
|
||||
new float[] {
|
||||
middle - height, middle + height, middle + nextHeight,
|
||||
middle - height, middle + nextHeight, middle - nextHeight
|
||||
},
|
||||
6
|
||||
);
|
||||
}
|
||||
|
||||
public static float normalise(float value, float min, float max) {
|
||||
return (value - min) / (max - min);
|
||||
}
|
||||
|
||||
public static float map(float value, float min, float max, float mMin, float mMax) {
|
||||
float norm = normalise(value, min, max);
|
||||
return (mMax - mMin) * norm + mMin;
|
||||
}
|
||||
|
||||
private static int clamp(int value, int min, int max) {
|
||||
return Math.max(Math.min(value, max), min);
|
||||
}
|
||||
|
||||
public enum Resizer implements Serializable {
|
||||
|
||||
NEAREST_NEIGHBOR {
|
||||
@Override
|
||||
public BufferedImage resize(BufferedImage source,
|
||||
int width, int height) {
|
||||
return commonResize(source, width, height,
|
||||
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
|
||||
}
|
||||
},
|
||||
BILINEAR {
|
||||
@Override
|
||||
public BufferedImage resize(BufferedImage source,
|
||||
int width, int height) {
|
||||
return commonResize(source, width, height,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
}
|
||||
},
|
||||
BICUBIC {
|
||||
@Override
|
||||
public BufferedImage resize(BufferedImage source,
|
||||
int width, int height) {
|
||||
return commonResize(source, width, height,
|
||||
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
}
|
||||
},
|
||||
PROGRESSIVE_BILINEAR {
|
||||
@Override
|
||||
public BufferedImage resize(BufferedImage source,
|
||||
int width, int height) {
|
||||
return progressiveResize(source, width, height,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
}
|
||||
},
|
||||
PROGRESSIVE_BICUBIC {
|
||||
@Override
|
||||
public BufferedImage resize(BufferedImage source,
|
||||
int width, int height) {
|
||||
return progressiveResize(source, width, height,
|
||||
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
}
|
||||
},
|
||||
AVERAGE {
|
||||
@Override
|
||||
public BufferedImage resize(BufferedImage source,
|
||||
int width, int height) {
|
||||
Image img2 = source.getScaledInstance(width, height,
|
||||
Image.SCALE_AREA_AVERAGING);
|
||||
BufferedImage img = new BufferedImage(width, height,
|
||||
source.getType());
|
||||
Graphics2D g = img.createGraphics();
|
||||
try {
|
||||
g.drawImage(img2, 0, 0, width, height, null);
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
return img;
|
||||
}
|
||||
};
|
||||
|
||||
public abstract BufferedImage resize(BufferedImage source,
|
||||
int width, int height);
|
||||
|
||||
private static BufferedImage progressiveResize(BufferedImage source,
|
||||
int width, int height, Object hint) {
|
||||
int w = Math.max(source.getWidth()/2, width);
|
||||
int h = Math.max(source.getHeight()/2, height);
|
||||
BufferedImage img = commonResize(source, w, h, hint);
|
||||
while (w != width || h != height) {
|
||||
BufferedImage prev = img;
|
||||
w = Math.max(w/2, width);
|
||||
h = Math.max(h/2, height);
|
||||
img = commonResize(prev, w, h, hint);
|
||||
prev.flush();
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
private static BufferedImage commonResize(BufferedImage source,
|
||||
int width, int height, Object hint) {
|
||||
BufferedImage img = new BufferedImage(width, height,
|
||||
source.getType());
|
||||
Graphics2D g = img.createGraphics();
|
||||
try {
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
|
||||
g.drawImage(source, 0, 0, width, height, null);
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
115
Java/Raycaster/src/main/java/de/craftix/raycaster/Window.java
Normal file
115
Java/Raycaster/src/main/java/de/craftix/raycaster/Window.java
Normal file
@@ -0,0 +1,115 @@
|
||||
package de.craftix.raycaster;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferStrategy;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class Window extends Canvas {
|
||||
public static JFrame frame;
|
||||
private final BufferStrategy buffer;
|
||||
private final Player player;
|
||||
|
||||
public static BufferedImage map;
|
||||
private static Graphics2D currentGraphics;
|
||||
|
||||
public static float deltaTime;
|
||||
private int fps;
|
||||
|
||||
private final int scalingFactor = 1;
|
||||
private final boolean minimap = true;
|
||||
|
||||
public Window(String title, Dimension dimensions) throws Exception {
|
||||
frame = new JFrame();
|
||||
frame.setVisible(false);
|
||||
frame.setTitle(title);
|
||||
frame.setSize(dimensions);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.add(this);
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setVisible(true);
|
||||
createBufferStrategy(3);
|
||||
buffer = getBufferStrategy();
|
||||
|
||||
map = ImageIO.read(Raycaster.class.getClassLoader().getResourceAsStream("map.png"));
|
||||
scaledMap = map.getScaledInstance(map.getWidth() / scalingFactor, map.getHeight() / scalingFactor, Image.SCALE_DEFAULT);
|
||||
player = new Player();
|
||||
addKeyListener(player);
|
||||
frame.addWindowStateListener(e -> {
|
||||
Player.updateRays = true;
|
||||
});
|
||||
requestFocus();
|
||||
new Thread(this::UpdateThread).start();
|
||||
}
|
||||
|
||||
private void UpdateThread() {
|
||||
long lastFrame = System.nanoTime();
|
||||
long lastFPSUpdate = System.currentTimeMillis();
|
||||
int frameCount = 0;
|
||||
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
long now = System.nanoTime();
|
||||
deltaTime = (System.nanoTime() - lastFrame) / 1000000000f;
|
||||
lastFrame = now;
|
||||
|
||||
Update();
|
||||
Graphics2D g = (Graphics2D) buffer.getDrawGraphics();
|
||||
currentGraphics = g;
|
||||
Render(g);
|
||||
|
||||
if (now - lastFPSUpdate >= 1000000000) {
|
||||
fps = frameCount;
|
||||
lastFPSUpdate = now;
|
||||
frameCount = 0;
|
||||
System.out.println("FPS: " + fps);
|
||||
}
|
||||
|
||||
buffer.show();
|
||||
frameCount++;
|
||||
}
|
||||
|
||||
buffer.dispose();
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
player.Update();
|
||||
}
|
||||
|
||||
private Image scaledMap;
|
||||
private void Render(Graphics2D g) {
|
||||
currentGraphics = g;
|
||||
g.setColor(Color.BLACK);
|
||||
g.fillRect(0, 0, frame.getWidth(), frame.getHeight());
|
||||
|
||||
int middle = frame.getHeight() / 2;
|
||||
for (int y = 0; y < frame.getHeight(); y++) {
|
||||
int dist = Math.abs(middle - y);
|
||||
int brightness = (int) Raycaster.map(dist, 0, middle, 0, 100);
|
||||
g.setColor(new Color(brightness, brightness, brightness, 255));
|
||||
g.drawLine(0, y, frame.getWidth(), y);
|
||||
}
|
||||
|
||||
player.Render(g);
|
||||
|
||||
//Render Minimap
|
||||
if (minimap) {
|
||||
int yOffset = frame.getHeight() - scaledMap.getHeight(null) - 50;
|
||||
g.drawImage(scaledMap, 0, yOffset, null);
|
||||
g.setColor(Color.RED);
|
||||
g.fillRect((int) Player.position.getX() / scalingFactor - 2, (int) Player.position.getY() / scalingFactor + yOffset - 2, 4, 4);
|
||||
}
|
||||
|
||||
g.setColor(Color.LIGHT_GRAY);
|
||||
g.fillRect(0, 0, 100, 50);
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawString("FPS: " + fps, 5, 15);
|
||||
g.drawString("Resolution: " + Raycaster.resolution, 5, 30);
|
||||
g.drawString("FOV: " + Raycaster.fov, 5, 45);
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
public static Graphics2D getCurrentGraphics() {
|
||||
return currentGraphics;
|
||||
}
|
||||
}
|
||||
BIN
Java/Raycaster/src/main/resources/map.png
Normal file
BIN
Java/Raycaster/src/main/resources/map.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
Reference in New Issue
Block a user