Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import javax.swing.*;
- import java.awt.*;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.awt.event.KeyEvent;
- import java.awt.event.KeyListener;
- import java.awt.image.BufferStrategy;
- import java.awt.image.BufferedImage;
- import java.awt.image.DataBufferInt;
- import java.io.File;
- import java.util.ArrayList;
- import java.util.Random;
- import javax.imageio.ImageIO;
- public class Main implements Runnable {
- final int WIDTH = 1024, HEIGHT = 768;
- final double ROT_SHIFT = 0.007;
- final String TITLE = "Pseudo-3D";
- JFrame frame;
- Canvas canvas;
- BufferedImage screenBuffer;
- Thread t;
- boolean running;
- int[] screen;
- Graph graphics;
- double rot = 0;
- double posX = 0, posY = 0;
- public void run() {
- graphics = new Graph(WIDTH, HEIGHT);
- while (running) {
- graphics.draw(rot, posX, posY);
- // Скопируем отрендеренное изображение
- System.arraycopy(graphics.pixels, 0, screen, 0, WIDTH * HEIGHT);
- // Отрисуем буфер на экран
- BufferStrategy bs = canvas.getBufferStrategy();
- Graphics g = bs.getDrawGraphics();
- g.drawImage(screenBuffer, 0, 0, WIDTH, HEIGHT, null);
- g.dispose();
- bs.show();
- }
- }
- public Main() {
- running = false;
- frame = new JFrame();
- canvas = new Canvas();
- frame.add(canvas);
- frame.pack();
- canvas.addKeyListener(new KeyListener() {
- @Override
- public void keyTyped(KeyEvent e) {
- }
- @Override
- public void keyPressed(KeyEvent e) {
- switch (e.getKeyCode()) {
- case KeyEvent.VK_LEFT: rot -= ROT_SHIFT; break;
- case KeyEvent.VK_RIGHT: rot += ROT_SHIFT; break;
- case KeyEvent.VK_W:
- posX += Math.cos(rot);
- posY += Math.sin(rot);
- break;
- case KeyEvent.VK_A:
- posY -= Math.cos(rot);
- posX += Math.sin(rot);
- break;
- case KeyEvent.VK_S:
- posX -= Math.cos(rot);
- posY -= Math.sin(rot);
- break;
- case KeyEvent.VK_D:
- posY += Math.cos(rot);
- posX -= Math.sin(rot);
- break;
- }
- }
- @Override
- public void keyReleased(KeyEvent e) {
- }
- });
- frame.setFocusable(true);
- frame.setFocusTraversalKeysEnabled(false);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setSize(WIDTH, HEIGHT);
- frame.setResizable(false);
- frame.setLocationRelativeTo(null);
- frame.setTitle(TITLE);
- frame.setVisible(true);
- canvas.createBufferStrategy(3);
- screenBuffer = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
- screen = ((DataBufferInt)screenBuffer.getRaster().getDataBuffer()).getData();
- running = true;
- t = new Thread(this);
- t.start();
- }
- public static void main(String[] args) {
- new Main();
- }
- // Стена с началом в (x, z) и концом в (xRight, z)
- private class Wall {
- public double x, z, xRight;
- public Wall(double a, double b, double xEnd) {
- x = a;
- z = b;
- xRight = xEnd;
- }
- }
- private class Graph {
- int width, height, imageWidth, imageHeight;
- public int[] pixels;
- ArrayList<Wall> walls;
- double imageScale = 0, stepScale = 0;
- BufferedImage img;
- public Graph(int width, int height) {
- pixels = new int[width * height];
- this.width = width;
- this.height = height;
- try {
- img = ImageIO.read(new File("C:\\Work\\1.bmp"));
- } catch (Exception e) {
- e.printStackTrace();
- }
- walls = new ArrayList<Wall>();
- walls.add(new Wall(-1, 6, 1));
- imageWidth = img.getWidth();
- imageHeight = img.getHeight();
- imageScale = Math.sqrt(imageWidth * imageHeight);
- stepScale = Math.sqrt(imageWidth * imageHeight) / 20.;
- }
- void draw(double rot, double posX, double posY) {
- posX *= stepScale;
- posY *= stepScale;
- // Тут начинается магия
- double _cos = Math.cos(rot), _sin = Math.sin(rot);
- for (int y = 0; y < height; ++y) {
- // https://www.wolframalpha.com/input/?i=%28y-384%29%2F384
- double ceiling = Math.abs((y - height / 2.) / height);
- // Тут отображаем "глубину" относительно y
- // https://www.wolframalpha.com/input/?i=1%2F%28%28y-384%29%2F384%29
- double z = imageScale * Math.abs(height / (y - height / 2.));
- double brightness = 1;
- if (Math.abs(y - height/ 2) < 100.) {
- // Обрежем вид относительно дальности: (|y-height/2|/80)^2
- // На выходе - коэффициент "светлости" (brightness) пикселя
- // можно попробовать поэксперементировать с
- // логарифмированием этой штуки и выбрать вариант,
- // более приятный глазу.
- brightness = Math.abs(y - height / 2.) / 100.;
- brightness *= brightness * brightness;
- }
- for (int x = 0; x < width; ++x) {
- double depth = (x - width / 2.) * Math.abs(imageScale / (y - height / 2.));
- // https://www.wolframalpha.com/input/?i=1%2F%28%28y-384%29%2F384%29+*+%28x+-+512%29%2F512
- // можно посмотреть на график тут. Мы его "примерно" отображаем на наш экран
- // Высчитываем a и b - координаты в картинке, которая заливает пол и потолок
- //System.out.println(z);
- int a = Math.abs((int)(depth * _cos + z * _sin + posY)) % (imageWidth);
- int b = Math.abs(((int)(z * _cos - depth * _sin + posX))) % (imageHeight);
- //pixels[x + y * width] = a;
- int rgb = img.getRGB(a, b);
- // Домножим каждую компоненту цвета на яркость
- rgb = ((int)((rgb & 0xFF) * brightness)) | ((int)(((rgb & 0xFF00) >> 8) * brightness)) << 8
- | ((int)(((rgb & 0xFF0000) >> 16) * brightness)) << 16;
- pixels[x + y * width] = rgb;
- }
- }
- drawWalls(rot, posX, posY);
- }
- void drawWalls(double rot, double posX, double posY) {
- posX /= stepScale;
- posY /= stepScale;
- double _cos = Math.cos(rot), _sin = Math.sin(rot);
- Random r = new Random();
- for (int i = 0; i < walls.size(); ++i) {
- Wall w = walls.get(i);
- double xLeft = w.x * 20;
- double xRight = w.xRight * 20;
- double zDistance = w.z * 20;
- double yHeight = 40; // 2 блока
- double xcLeft = (xLeft - posY) * 2;
- double zcLeft = (zDistance - posX) * 2;
- double rotLeftSideX = _cos * xcLeft - _sin * zcLeft;
- double yCornerTL = -yHeight;
- double yCornerBL = (yHeight);
- double rotLeftSideZ = _cos * zcLeft + _sin * xcLeft;
- double xcRight = (xRight - posY) * 2;
- double zcRight = (zDistance - posX) * 2;
- double rotRightSideX = xcRight * _cos - zcRight * _sin;
- double yCornerTR = (-yHeight);
- double yCornerBR = (yHeight);
- double rotRightSideZ = zcRight * _cos + xcRight * _sin;
- double xPixelLeft = rotLeftSideX / rotLeftSideZ * height + width / 2;
- double xPixelRight = (rotRightSideX / rotRightSideZ * height + width / 2);
- if (xPixelLeft >= xPixelRight) {
- return;
- }
- int xPixelLeftInt = (int)(xPixelLeft);
- int xPixelRightInt = (int)(xPixelRight);
- xPixelLeftInt = Math.max(0, xPixelLeftInt);
- xPixelRightInt = Math.min(width, xPixelRightInt);
- double yPixelLeftTop = (int) (yCornerTL / rotLeftSideZ * height + height / 2);
- double yPixelLeftBottom = (int) (yCornerBL / rotLeftSideZ * height + height / 2);
- double yPixelRightTop = (int) (yCornerTR / rotRightSideZ * height + height / 2);
- double yPixelRightBottom = (int) (yCornerBR / rotRightSideZ * height + height / 2);
- //System.out.println(rotLeftSideX + " " +rotLeftSideZ+ " " +xPixelLeft + " " + xPixelRight);
- for (int x = xPixelLeftInt; x < xPixelRightInt; ++x) {
- double pixelRotation = (x - xPixelLeft) / (xPixelRight - xPixelLeft);
- double yPixelTop = Math.max(0, yPixelLeftTop + (yPixelRightTop - yPixelLeftTop) * pixelRotation);
- double yPixelBottom = Math.min(height, yPixelLeftBottom + (yPixelRightBottom - yPixelLeftBottom) * pixelRotation);
- //System.out.println(yPixelBottom - yPixelTop);
- for (int y = (int) yPixelTop; y < yPixelBottom; ++y) {
- pixels[x + y * width] = 0xAAAAAA;
- }
- }
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement