# Figur zentrieren und Spielwelt erstellen



## AlphaBerta (10. Nov 2017)

Bräuchte hilfe bei einem kleinen spiel das ich programmiere:
Würde gerne eine spielwelt erstellen, weiß wie man einzelne blöcke einfügt, jedoch nicht wie ich ein ganzes Level erstelle. Außerdem würde ich es gerne so haben das man sich als Spielfigur auf diesem Level bewegt, wobei die Kamera immer auf einen selbst zentriert ist, im Moment bewegt sich der Charakter und nicht das Level unter einem.
Code Game-Klasse :

```
package com.projekt.x;

import java.awt.Canvas;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JFrame;

import com.projekt.x.entity.Entity;
import com.projekt.x.entity.Player;
import com.projekt.x.graphics.Sprite;
import com.projekt.x.graphics.SpriteSheet;
import com.projekt.x.input.Keyboard;
import com.projekt.x.tile.GrassTile;
import com.projekt.x.tile.Ground;
import com.projekt.x.tile.Tile;

public class Game extends Canvas implements Runnable {
    private static final long serialVersionUID = 1L;

    public static final int width = 300;
    public static final int height = width / 16 * 9 + 16;
    public static final int scale = 3;
    public static final String title = "Projekt - X";
    public static int pixelScale = 2;

    private Thread thread;
    private JFrame frame;
    private Keyboard key;
    private boolean running = false;
    private double SheetSize = 48;
   
    private BufferedImage image = new BufferedImage(width, height,
            BufferedImage.TYPE_INT_ARGB); // Ein Bild mit einem
                                            // "Puffer" ||
                                            // Rastser ist Array
                                            // von Pixeln des
                                            // Bilds

    private BufferedImage background;
    private final float backgroundSpeed = 3 / 4f;

    public static SpriteSheet tileSprites = new SpriteSheet(
            "/textures/spritesheet.png");
    public static SpriteSheet megaman = new SpriteSheet("/textures/megaman_sheet.png");
    public static SpriteSheet megaman01 = new SpriteSheet("/textures/megaman_sheet01.png");
    public static Sprite grass = new Sprite(4, 1, 1, 1, tileSprites);
    public static Sprite playerSprite[] = new Sprite[3];
    public static Sprite playerSprite01[] = new Sprite[3];


    private ArrayList<Tile> tiles;
    private ArrayList<Entity> entities;

    private Player player;
    private Player player01;


    public Game() {
        Dimension size = new Dimension(width * scale, height * scale);
        setPreferredSize(size);

        // load background image
        try {
            background = ImageIO.read(Game.class
                    .getResource("/textures/background.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        frame = new JFrame();
        key = new Keyboard();
        tiles = new ArrayList<Tile>();
        tiles.add(new GrassTile(180, 350, 32, 32, grass));
        tiles.add(new GrassTile(300, 250, 32, 32, grass));
        tiles.add(new GrassTile(420, 150, 32, 32, grass));
        for (int i = 0; i < 100; i++) {
            tiles.add(new Ground(i * 16 * pixelScale, 502, 32, 32, grass));
        }

        for (int i = 0; i < playerSprite.length; i++) {
            playerSprite[i] = new Sprite(3 + i, 1, 1f, 1f, megaman,0);
        }
        entities = new ArrayList<Entity>();
        player = new Player(100, 100, 32, 64, playerSprite, key, this);
        entities.add(player);
        addKeyListener(key);
       
        for (int i = 0; i < playerSprite01.length; i++) {
            playerSprite01[i] = new Sprite(20 + i, 1, 1f, 1f, megaman01,0);
        }
        entities = new ArrayList<Entity>();
        player01 = new Player(100, 100, 32, 64, playerSprite01, key, this);
        entities.add(player01);
        addKeyListener(key);
    }

    public synchronized void start() {
        running = true;
        thread = new Thread(this, "Display");
        thread.start();
    }

    public synchronized void stop() {
        running = false;
        try /**me bitch**/ {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void run() { // weil Runnable implementiert wird, wird diese Methode
                        // beim start aufgerufen
        long lastTime = System.nanoTime(); // wenn sich das system öffnet
                                            // erhalten wir die jetzige Zeit in
                                            // nano sekunden
        long timer = System.currentTimeMillis();
        final double ns = 1000000000.0 / 60.0; // 60 => spiel wird 60 mal die
                                                // Sekunde ge-updated
        double delta = 0;
        int frames = 0; // zählt wie viel frames wir pro Sekunde rendern
        int updates = 0; // wie oft wird update Methode pro Sekunde aufgerufen
        requestFocus(); // um die Eingaben direkt auf das Fenster zu fokussieren
        while (running) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while (delta >= 1) {
                update();
                updates++;
                delta--;
            }
            render();
            frames++;

            if (System.currentTimeMillis() - timer > 1000) { // passiert 1 mal
                                                                // die Sekunde
                timer += 1000;
                System.out.println(updates + " ups , " + frames + " fps");
                frame.setTitle(title + "   |   " + updates + " ups , " + frames
                        + " fps");
                updates = 0; // damit die ups und fps nicht addiert werden
                frames = 0; // damit die ups und fps nicht addiert werden
            }
        }
        stop();
    }

    int x = 0, y = 0;

    public void update() {
        key.update();
        player.update();
        player01.update();
        for (Tile tile : tiles) {
            tile.update();
        }
        if (key.right) {
            x += 2 * pixelScale;
            player.setMoving(true);
        }
        else if (key.left) {
            x -= 2 * pixelScale;
            player01.setMoving(true);
        }else{
            player01.setMoving(false);
        }
        if (x < 0)
            x = 0;
    }

    public void render() {
        BufferStrategy bs = getBufferStrategy();
        if (bs == null) {
            createBufferStrategy(3);
            return;
        }

        Graphics g = bs.getDrawGraphics();
        // Draw background
        int mx = (int) (player.getX() / 2 * backgroundSpeed)
                % background.getWidth();
        int offset = 0;
        if (mx < 0)
            offset = -(background.getWidth() + mx);
        else
            offset = background.getWidth() - mx;

        g.drawImage(background, offset,
                (height * scale - background.getHeight()) - 32, null);
        g.drawImage(background, offset - background.getWidth(), (height * scale
                - background.getHeight() - 32), null);

        for (Entity entity : entities) {
            entity.render(g);
        }
        for (Tile tile : tiles) {
            tile.render(g);
        }

        // Draw sprites
        g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
        g.dispose();
        bs.show();
    }

    public static void main(String[] args) {
        Game game = new Game();
        game.frame.setResizable(false);
        game.frame.setTitle(Game.title);
        game.frame.add(game);
        game.frame.pack();
        game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        game.frame.setLocationRelativeTo(null);
        game.frame.setVisible(true);

        game.start();

    }

    public ArrayList<Tile> getTiles() {
        return tiles;
    }

}
```

Code Player-Klasse

```
package com.projekt.x.entity;

import java.awt.Color;

import java.awt.Graphics;

import com.projekt.x.Game;
import com.projekt.x.graphics.Sprite;
import com.projekt.x.input.Keyboard;
import com.projekt.x.tile.GrassTile;
import com.projekt.x.tile.Tile;

public class Player extends Entity {

    private Keyboard key;
    private Game game;

    private final float GRAVITY = 0.4f;
    private final float JUMP_STRENGTH = 11;

    private boolean inAir;
    private boolean canJump;

    private float vy;
    private int ground;
    private boolean canMoveLeft;
    private boolean canMoveRight;
    private boolean isMoving = false;
    private boolean isJumping = false;
    private int prevX;

    private int frame = 0;
    private int frameMax;
    private int animSpeed = 4;

    public Player(int x, int y, int w, int h, Sprite[] sprite, Keyboard key, Game game) {
        super(x, y, w, h, sprite);
        this.key = key;
        this.game = game;
        this.frameMax = sprite.length - 1;
        ground = Integer.MAX_VALUE;
        prevX = x;
    }

    @Override
    public void render(Graphics g) {
        if (isMoving) {
            g.drawImage(sprite[frame].getImage(), x - 8, y + 16, getW() + 30, getH() + 16, null);
        } else {
            g.drawImage(sprite[0].getImage(), x - 8, y + 16, getW() + 30, getH() + 16, null);
        }
        if (isJumping) {

        }
        // left
        // g.setColor(Color.black);
        // g.drawRect(x+24, y + 5 * Game.pixelScale+getH()/2, w * Game.pixelScale - (27
        // *
        // Game.pixelScale),
        // h * Game.pixelScale - 10 * Game.pixelScale-getH()/2);
        // // right
        // g.setColor(Color.green);
        // g.drawRect(x + 27 * Game.pixelScale, y +getH()/2+ 5 * Game.pixelScale, w *
        // Game.pixelScale - (27 * Game.pixelScale),
        // h * Game.pixelScale - 10 * Game.pixelScale-getH()/2);
        // // top
        // g.setColor(Color.red);
        // g.drawRect(x + 5 * Game.pixelScale+22, y+getH()/2, -20+w * Game.pixelScale -
        // 10 *
        // Game.pixelScale,
        // h * Game.pixelScale - (59 * Game.pixelScale));
        // // bottom
        // g.setColor(Color.blue);
        // g.drawRect(x +22+ 5 * Game.pixelScale, y + 59 * Game.pixelScale, w *
        // Game.pixelScale - 20-10 * Game.pixelScale,
        // h * Game.pixelScale - (59 * Game.pixelScale));
    }

    int delay = 0;

    @Override
    public void update() {

        if (delay % animSpeed == 0) {
            if (frame < frameMax) {
                frame++;
            } else {
                frame = 0;
            }
            delay++;
        } else {
            delay++;
        }
        y += vy;

        canMoveRight = true;
        canMoveLeft = true;
        boolean collision = false;
        for (Tile tile : game.getTiles()) {
            if (key.right) {
                if (!tile.leftCollision().intersects(rightCollision())) {
                } else {
                    collision = true;
                    canMoveRight = false;
                }
            } else {
                canMoveRight = false;
            }
            if (key.left) {
                if (!tile.rightCollision().intersects(leftCollision())) {
                } else {
                    collision = true;
                    canMoveLeft = false;
                }
            } else {
                canMoveLeft = false;
            }
            if (tile.topCollision().intersects(bottomCollision())) {
                ground = tile.getY() - tile.getH() * Game.pixelScale;
                collision = true;
            } else {

            }
            if (tile.bottomCollision().intersects(topCollision())) {
                collision = true;
                vy = 0;
                y += 5;
            }
        }

        if (!collision) {
            ground = Integer.MAX_VALUE;
            canJump = false;
        }
        if (canMoveRight)
            x += 3 * Game.pixelScale;
        if (canMoveLeft)
            x -= 3 * Game.pixelScale;
        // Jump
        if (y < ground) {
            inAir = true;
            vy += GRAVITY;
        } else if (y >= ground && inAir) {
            inAir = false;
            y = ground;
            vy = 0;
            canJump = true;
        }

        if (canJump && key.up) {
            canJump = false;
            vy = -JUMP_STRENGTH;
        }
        if (x < 0) {
            x = 0;
        }
        prevX = x;
    }

    public boolean isInAir() {
        return inAir;
    }

    public void setInAir(boolean inAir) {
        this.inAir = inAir;
    }

    public void setVy(float vy) {
        this.vy = vy;
    }

    public float getVy() {
        return vy;
    }

    public Keyboard getKey() {
        return key;
    }

    public void setKey(Keyboard key) {
        this.key = key;
    }

    public boolean isCanJump() {
        return canJump;
    }

    public void setCanJump(boolean canJump) {
        this.canJump = canJump;
    }

    public int getGROUND() {
        return ground;
    }

    public float getGRAVITY() {
        return GRAVITY;
    }

    public float getJUMP_STRENGTH() {
        return JUMP_STRENGTH;
    }

    public void setMoving(boolean moving) {
        isMoving = moving;
    }

}
```

Ich denke um ein Level zu erstellen muss man nur ein ArrayList<Tile> füllen und dann immer beim aufrufen zeichnen lassen, bei der Kamera weiß ich nicht genau wie ich das ändern kann. Zudem würde ich gerne die Level in einem anderen Package erstellen, sodass es übersichtlich bleibt. Falls ihr weiteren Code oder Infos braucht schnell sagen.
LG Jakob


----------



## BrknDevee (11. Nov 2017)

Ich habe bis jetzt immer nur eine Textur in z.B. paint.net gemacht, aus der dann das Level erstellt wird, das funktioniert ganz gut und man kann schnell neue Levels machen.

Du hast dann eine RGB Farbe von (0,0,0) bis (255, 255, 255), du könntest also z.B. um ein Gras Tile zu machen die Farbe (1,0,0) nehmen und damit dein Level (Antialiasing aus!) einfach zeichnen.
Im Code findest du dann die Breite und Höhe der Textur heraus und guckst mit einer doppelten for- Schleife alle Pixel durch und überall, wo die Farbe des Pixels (1,0,0) ist, setzt du ein Gras Tile. Du könntest dann das gleiche z.B. mit einem Wasser Tille bei z.B. (2,0,0) machen, etc.

Du könntest das dann auch mit Entities machen, z.B. ein Spieler als (0,0,1), etc. (Ich würde dann einen anderen Kanal nehmen, wie hier blau statt rot, der Übersichtlichkeit halber)

Dann müsstest du keine ArrayList per Hand machen.

In etwa so:

```
public World(String world) {
  try {
   SystemCreator file = new SystemCreator();
   BufferedImage tileSheet = ImageIO.read(new File(file.getWorkingDir() + "/ressources/maps/" + world + "/tiles.png"));
   World.tileSheet = tileSheet;
   width = tileSheet.getWidth();
   height = tileSheet.getHeight();
   
   this.worldMatrix = new Matrix4f().setTranslation(new Vector3f(0));
   this.worldMatrix.scale(scale);
   
   int[] colorTileSheet = tileSheet.getRGB(0, 0, width, height, null, 0, width);
   
   tiles = new byte[width * height];
   collisionBoxes = new AABB[width * height];
   
   for(int y = 0; y < height; y++) {
    for(int x = 0; x < width; x++) {
     int red = (colorTileSheet[x + y * width] >> 16) & 0xFF; //Will return the red component, eg here 1
     
     Tile t; //check tiles[] (must be equal to the number of different tiles used)
     try {
      t = Tile.tiles[red];
     }catch(ArrayIndexOutOfBoundsException e) {
      t = null;
     }
     if(t != null) {
      setTile(t, x, y);
     }
    }
   }
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
```


----------

