Tilemap Kollision

JTryn

Mitglied
Hallo,

ich muss mal wieder um eure Hilfe bitten bei einem Problem, das wies aussieht aber eher mathematisch bedingt ist als java-technisch. Ich habe dazu nun schon sehr viel Recherche betrieben
aber konnte nirgends was zu meinem Problem finden.

Ich habe eine völlig normale Tilemap, die anhand einer Map-Matrix gezeichnet wird, also:
map[breite][höhe][ebene]
Diese zeichne ich also in einer verschachtelten for-schleife, klappt auch alles prima,
aber die Probleme treten dann bei der Kollision auf.

Vereinfacht beschreibe ich das ganze mal mit einer einzelnen nicht-begehbaren Grafik:
Ich überprüfe also, ob diese Grafik sich über den Spieler befindet, links von ihm, rechts von ihm
oder unter ihm, was Dank der Map-Matrix ja eigentlich kein Problem darstellen sollte:
Java:
if (map_mov[map[(px+32-movspeed)/32-1][py/32][0]] == false){
   move_left = false;
}
if(map_mov[map[px/32+1][py/32][0]] == false){
   move_right = false;
}
if(map_mov[map[px/32][py/32+1][0]] == false){
   move_down = false;
}
if(map_mov[map[px/32][(py+32-movspeed)/32-1][0]] == false){
   move_up = false;
}

//Bewegung
            
if (move_right){
   px+=movspeed;
}else if(move_left){
   px-=movspeed;
}else if(move_down){
   py+=movspeed;
}else if(move_up){
   py-=movspeed;
}

//Tastaturabfrage
switch (ke.getKeyCode()) {
	case KeyEvent.VK_RIGHT: {
		move_right = true;
			if (move_up != true && move_down != true || map_mov[map[px/32+1][py/32][0]] != false ){
			move_left = false;
			move_up = false;
			move_down = false;
		}
	}
	break;
	
	case KeyEvent.VK_LEFT: {     	
		move_left = true;
			if (move_up != true && move_down != true || map_mov[map[px/32-1][py/32][0]] != false){
			move_right = false;
			move_down = false;
			move_up = false;
		}
	}
	break;
	
	case KeyEvent.VK_DOWN: {     	
		move_down = true;
			if (move_left != true && move_right != true || map_mov[map[px/32][py/32+1][0]] != false){
			move_left = false;
			move_right = false;
			move_up = false;
		}
	}
	break;  
	 
	case KeyEvent.VK_UP: {
		move_up = true;
			if (move_left != true && move_right != true || map_mov[map[px/32][py/32-1][0]] != false){
			move_down = false;
			move_left = false;
			move_right = false;
		}
	}
	break;    
	
	}
}

Beim ersten mal traten dabei schon einmal Probleme mit der Abfrage nach links und oben auf;
die Spielerfigur hat viel zu früh aufgehört sich zu bewegen, was höchstwahrscheinlich mit
Ungenauigkeiten bei der Teilung zu tun hat. Ich habe mir die Werte ausgeben lassen und musste
dann feststellen, dass die Nachkommastellen wegen des Datentyps int abgetrennt werden und
somit schon viel früher davon ausgegangen wird, dass sich die Spielfigur in einem Feld weiter oben
bzw. links befindet.
Um den zu entgehen habe ich links bei der X-Koordinate und oben bei der Y-Koordinate den Wert
32-4 hinzuaddiert, der sich scheinbar aus der Größe eines Tiles - dem Bewegungstempo ergibt.

Das behebt die Kollisionsprobleme links und über der Spielfigur, aber unabhängig davon tereten noch
an anderen Stellen Probleme mit der Kollision auf für die ich nun schon seit mehreren Stunden keine
Lösung finde... hierzu dieses Bild

ImageShack® - Online Photo and Video Hosting

Sagen wir die Lücke befindet sich an Stelle 6/1 in der Matrix.
Die Spielfigur bewegt sich geradlinig nach rechts (Kollision nach unten und oben funktioniert, wie gesagt). Jetzt kann sich die Spielfigur erst nach unten bewegen, wenn für den Wert SpielerX/32
genau 6.0 rauskommt. Leider aber auch für alles darüber - bewegen soll sie sich aber nun mal nur
bei 6.0.

In diesem Beispiel stoppt die Figur bei allem über 6.0, es scheint also schon fast richtig zu sein,
aber irgendwo ist noch ein Fehler. Was mich am meisten verwundert ist, dass ich hier nun
in der Tastaturabfrage nicht den Wert 32-4 addiere. Tu ich es verschiebt sich diese 'Kollisionslücke'
auf die linke Seite - es klappt dann rechts, aber links nicht.

Vielen Dank schon einmal an die, die sich die Mühe gemacht haben bis hierhin zu lesen. Sollte
irgendetwas unklar sein möchte ich mich entschuldigen - aber ich finde einfach nicht den Fehler
in meiner Logik.

Grüße, JTryn
 

Marco13

Top Contributor
Was sind denn das für Zahlen? ???:L 32-4 ?! Warum nicht 32-3.132?
Ich nehme mal an, dass die Position des Spielers als px,py in PIXELkoordinaten gespeichert ist, und die obere Linke Ecke des "Spieler-Tiles" beschreibt, und dass ein Tile 32x32 pixel groß ist - stimmt das so weit? Dann sollte man doch die Indizes ausrechnen können...
 

Ariol

Top Contributor
Vorschlag:
Java:
boolean canMoveLeft(){
	return map_mov[map[(px+32-movspeed)/32-1][py/32][0]];
}
boolean canMoveRight(){
	return map_mov[map[px/32+1][py/32][0]];
}
boolean canMoveUp(){
	return map_mov[map[px/32][py/32+1][0]];
}
boolean canMoveDown(){
	return map_mov[map[px/32][(py+32-movspeed)/32-1][0]];
}

Java:
//Bewegung            
if (move_right){
   px+=movspeed;
}else if(move_left){
   px-=movspeed;
}else if(move_down){
   py+=movspeed;
}else if(move_up){
   py-=movspeed;
}

Java:
//Tastaturabfrage
switch (ke.getKeyCode()) {
    case KeyEvent.VK_RIGHT: {
        move_right = canMoveRight();
        move_left = false;
        move_up = false;
        move_down = false;
    }
    break;
    
    case KeyEvent.VK_LEFT: {     
        move_right = false;
        move_left = canMoveLeft();
        move_up = false;
        move_down = false;
        }
    }
    break;
    
    case KeyEvent.VK_DOWN: {  
		    move_right = false;
		    move_left = false;
		    move_up = false;
		    move_down = canMoveDown();
        }
    }
    break;  
     
    case KeyEvent.VK_UP: {
		    move_right = false;
		    move_left = false;
		    move_up = canMoveUp();
		    move_down = false;
        }
    }
    break;    
    
    }
}

Ich denke das deine boolean-Werte durcheinander gekommen sind.
 
B

bERt0r

Gast
Beim ersten mal traten dabei schon einmal Probleme mit der Abfrage nach links und oben auf;
die Spielerfigur hat viel zu früh aufgehört sich zu bewegen, was höchstwahrscheinlich mit
Ungenauigkeiten bei der Teilung zu tun hat.
Also ich schätze dass die Spielfigur laut deinem Code viel früher vor einem Hindernis aufhören muss sich zu bewegen, du fragst ja ab, ob auf (Position des Spielers + Geschwindigkeit) ein Hinderniss ist, wenn ja, Handbremse soweit ich das verstanden habe.
Ich weis nicht wie groß deine movespeed werden kann, aber sobald die >1 ist, passiert genau das. Deine +/*- 32 Rechnungen sind Meiner Meinung nach fehl am Platz, es sei denn du rechnest Pixel um oder so.
 

JTryn

Mitglied
Danke für die antworten! Der Vorschlag von Ariol hilft leider nicht, aber könnte schon einmal für mehr Struktur sorgen.
Ziel der ganzen Steuerung ist es, dass sie 'pacmanartig' ist, also, dass man sich immer bewegt (bis zur Kollision) und die Richtung durch Tastendruck ändert.

Die Größe der Grafiken ist 32x32, da kommt es her.

Durch 32 teile ich, damit ich die Spielerkoordinaten im Array bekomme.

Ich denke ich poste mal den gesamten Code, auch, wenn er recht unübersichtlich ist (daran arbeite
ich noch).. ich hoffe man es ist dann mehr verständlich

ScreenManager ist nur für die Öffnung des Vollbildschirms zuständig.

Java:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.*;

public class Main implements KeyListener {	
	
    private static DisplayMode modes[] = {
    	new DisplayMode(1024, 768, 32,0),
    	new DisplayMode(800, 600, 32,0),
        new DisplayMode(800, 600, 24,0),
        new DisplayMode(800, 600, 16,0),
        new DisplayMode(640, 480, 32,0),
        new DisplayMode(640, 480, 24,0),
        new DisplayMode(640, 480, 16,0),
    };
    
    private boolean running;
    protected ScreenManager s;
    //private Animation a;
    //protected Sprite sprite;
    
    
    
    //tile engine
    ArrayList<BufferedImage> tiles = new ArrayList<BufferedImage>();
    public BufferedImage face;
    public BufferedImage tile;
    public BufferedImage test;
    
	int map_width = 32;
	int map_height = 24;
	
	//map array
	int[][][] map = new int[map_width][map_height][3];
	//collision array
	boolean[] map_mov = new boolean[8];
	//player coll
	boolean move_right;
	boolean move_left;
	boolean move_down;
	boolean move_up;
	
	int px=32;
	int py=32;
	
	float fpx=px;
	float fpy=py;
	
	//player movement speed
	int movspeed = 4;
    
    String mess = "";
    
    public static void main(String[] args){
        Main c = new Main();
    	c.run();
    }

    //stop method
    public void stop() {
        running = false;
    }
    
    //call init and gameloop
    public void run() {
        try{
            init();     
            loadImages();
            loadMap();
            gameLoop();
 
        }finally{
            s.restoreScreen();
        }
    }
    
    //set to full screen
    public void init() {
        s = new ScreenManager();
        DisplayMode dm = s.findFirstCompatibleMode(modes);
        s.setFullScreen(dm);
        
        Window w = s.getFullScreenWindow();
        w.setFocusTraversalKeysEnabled(false);
        w.addKeyListener(this);
        w.setFont(new Font("Arial", Font.PLAIN, 20));
        w.setBackground(Color.BLACK);
        w.setForeground(Color.WHITE);
        running = true;
        
        mess = "press escape to exit";
    }
   
    //load images
    public void loadImages(){

		try {
			BufferedImage[] ntile = new BufferedImage[8];
			String s = "";
			for(int i=0; i<8; i++){
				s = String.format("gfx/100" + i + ".png");
				ntile[i] = ImageIO.read(new File(s));
				this.tiles.add(ntile[i]);
			}
			
			face = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
			face = ImageIO.read(new File("gfx/face.png"));

		}catch (IOException error){
			System.err.println("gfx not found");
			error.printStackTrace();
		}
        
        //face = new ImageIcon("gfx/face.png").getImage();
		
		
    }
    
    public void loadMap(){
		try {
			BufferedInputStream buf=new BufferedInputStream(new FileInputStream("testmap.test"));
			ObjectInputStream read = new ObjectInputStream(buf);

			map=(int[][][]) read.readObject();
			String name=(String) read.readObject();
			String fileName=(String) read.readObject();

			read.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
		}
		
		map_mov[0] = true;
		map_mov[1] = true;
		map_mov[2] = false;
		map_mov[3] = false;
		map_mov[4] = true;
		map_mov[5] = true;
    }
    
    public void playerMove(){
    	
    }
    
    //main gameLoop
    public void gameLoop() {
        long startTime = System.currentTimeMillis();
        long cumTime = startTime;
        
        while(running){
            long timePassed = System.currentTimeMillis() - cumTime;
            cumTime += timePassed;
            
            update(timePassed);
            
            Graphics2D g = s.getGraphics();
            draw(g);
            
            fpx=px;
            fpy=py;
            
            
            if (map_mov[map[(px+32-movspeed)/32-1][py/32][0]] == false){
            	   move_left = false;
            }
            	if(map_mov[map[px/32+1][py/32][0]] == false){
            	   move_right = false;
            }
            if(map_mov[map[px/32][py/32+1][0]] == false){
            	   move_down = false;
            }
            	if(map_mov[map[px/32][(py+32-movspeed)/32-1][0]] == false){
            	   move_up = false;
            }

            
            
            if (move_right){
            	   px+=movspeed;
            }else if(move_left){
            	   px-=movspeed;
            }else if(move_down){
            	   py+=movspeed;
            }else if(move_up){
            	   py-=movspeed;
            }

         	
            g.dispose();
            s.update();
            
            try{
                Thread.sleep(40);
            }catch(Exception ex){}
            
        }
    }
    
    //keyPressed
    public void keyPressed(KeyEvent ke){
    	int keyCode = ke.getKeyCode();
        if(keyCode == KeyEvent.VK_ESCAPE){
            stop();   
        }else if(keyCode== KeyEvent.VK_F1){
        	
        }else{
            mess = "Pressed : "+KeyEvent.getKeyText(keyCode);
            ke.consume();
        }	
        
    	
        switch (ke.getKeyCode()) {
	        case KeyEvent.VK_RIGHT: {
	            move_right = true;
	                if (move_up != true && move_down != true || map_mov[map[px/32+1][py/32][0]] != false ){
	                move_left = false;
	                move_up = false;
	                move_down = false;
	            }
	        }
	        break;
	        
	        case KeyEvent.VK_LEFT: {        
	            move_left = true;
	                if (move_up != true && move_down != true || map_mov[map[px/32-1][py/32][0]] != false){
	                move_right = false;
	                move_down = false;
	                move_up = false;
	            }
	        }
	        break;
	        
	        case KeyEvent.VK_DOWN: {        
	            move_down = true;
	                if (move_left != true && move_right != true || map_mov[map[px/32][py/32+1][0]] != false){
	                move_left = false;
	                move_right = false;
	                move_up = false;
	            }
	        }
	        break;  
	         
	        case KeyEvent.VK_UP: {
	            move_up = true;
	                if (move_left != true && move_right != true || map_mov[map[px/32][py/32-1][0]] != false){
	                move_down = false;
	                move_left = false;
	                move_right = false;
	            }
	        }
	        break;        
        }
    
    }
    
    
    //keyReleased
    public void keyReleased(KeyEvent e){
        int keyCode = e.getKeyCode();
        mess = "Released : "+KeyEvent.getKeyText(keyCode);
        e.consume();
    }
    
    //last method from interface
    public void keyTyped(KeyEvent e){
        e.consume();
    }
    
    //update animation
    public void update(long timePassed){
        
    }

    //draws to screen
    public void draw(Graphics2D g){
        Window w = s.getFullScreenWindow();
        
        g.setColor(w.getBackground());
        g.fillRect(0, 0, s.getWidth(), s.getHeight());
        g.setColor(w.getForeground());
        
	
		
    	for(int x=0;x < 31; x++){
			for(int y=0;y < 23;  y++){
				for(int z=0; z<=0; z++){
					if(map[x][y][z] != 0){				
						g.drawImage(tiles.get(map[x][y][z]), x*32, y*32, null);
					}	
				}
			}
		}	
        
        g.drawImage(face, px, py, null);
        
        //realtime debug
        g.drawString(mess, 30, 30);
        g.drawString(String.format(""+px), 30, 50);
        g.drawString(String.format(""+py), 30, 70);
        //collision
        g.drawString(String.format("PX32: "+fpx/32), 250, 30);
        g.drawString(String.format("PY32: "+fpy/32), 250, 50);
        if (px/32 != 0 && px/32 != 31){
        	g.drawString(String.format("Tile right: "+map[px/32+1][py/32][0]), 380, 30);
        	g.drawString(String.format("Tile left: "+map[px/32-1][py/32][0]), 380, 50);
        }
        if (py/32 != 0 && py/32 != 23){
        	g.drawString(String.format("Tile up: "+map[px/32][py/32-1][0]), 380, 70);
        	g.drawString(String.format("Tile down: "+map[px/32][py/32+1][0]), 380, 90);
        }
	}
    
    
}

Hier kann man gerade beim nach unten und beim nach links gehen über die blockierte
Felder laufen. Das map_mov-Array verwende ich momentan für die Kollision, geprüft wird,
ob das Feld den Wert false hat (wird noch optimiert). Aber daran kanns ja auch nicht liegen.
 

JTryn

Mitglied
Edit: Sehe gerade hier kann man auch Anhänge benutzen..

Dann fehlen auch die Grafiken und die Map. Sorry, mein Fehler.

War jetzt der beste Host, der mir einfiel
res.rar
(einfach in den root Ordner entpacken)

ScreenManager.java
Java:
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;

public class ScreenManager {

    private GraphicsDevice vc;
    
    // give vc access to monitor screen
    public ScreenManager() {
        GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
        vc = e.getDefaultScreenDevice();      
    }
    
    //get all compatible DM
    public DisplayMode[] getCompatibleDisplayModes() {
        return vc.getDisplayModes();
    }

    //compares DM passed in vc DM and see if they match
    public DisplayMode findFirstCompatibleMode(DisplayMode modes[]) {
        DisplayMode goodModes[] = vc.getDisplayModes();
        for(int x=0; x<modes.length; x++) {
            for(int y=0; y<goodModes.length;y++) {
                if(displayModesMatch(modes[x],goodModes[y])) {
                    return modes[x];
                }
            }
        }
        return null;
    }
            
    //get current DM
    public DisplayMode getCurrentDisplayMode() {
        return vc.getDisplayMode();       
    }
    
    //checks if two modes match each other
    public boolean displayModesMatch(DisplayMode m1, DisplayMode m2) {
        if(m1.getWidth() != m2.getWidth() || m1.getHeight() != m2.getHeight()){
            return false;
        }
        if(m1.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI && m2.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI && m1.getBitDepth() != m2.getBitDepth()){
            return false;
        }
        if(m1.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN && m2.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN && m1.getRefreshRate() != m2.getRefreshRate()){
            return false;
        }
        
        return true;
    }
    
    //make frame full screen
    public void setFullScreen(DisplayMode dm) {
        JFrame f = new JFrame();
        f.setUndecorated(true);
        f.setIgnoreRepaint(true);
        f.setResizable(false);
        vc.setFullScreenWindow(f);
        
        if(dm != null && vc.isDisplayChangeSupported()){
            try{
                vc.setDisplayMode(dm);
            }catch(Exception ex){}
        }
        f.createBufferStrategy(2);     
    }   
    
    //set graphics object = to this
    public Graphics2D getGraphics(){
        Window w = vc.getFullScreenWindow();
        if(w != null){
            BufferStrategy s = w.getBufferStrategy();
            return (Graphics2D)s.getDrawGraphics();
        }else{
            return null;
        }
    }
    
    //updates display
    public void update(){
        Window w = vc.getFullScreenWindow();
        if(w != null){
            BufferStrategy s = w.getBufferStrategy();
            if(!s.contentsLost()){
                s.show();
            }
        }
    }
    
    public Window getFullScreenWindow(){
        return vc.getFullScreenWindow();
    }
    
    //get width of window
    public int getWidth(){
        Window w = vc.getFullScreenWindow();
        if(w != null){
            return w.getWidth();
        }else{
            return 0;
        }
    }
    
    //get height of window
    public int getHeight(){
        Window w = vc.getFullScreenWindow();
        if(w != null){
            return w.getHeight();
        }else{
            return 0;
        }
    }
    
    //get out of full screen
    public void restoreScreen(){
        Window w = vc.getFullScreenWindow();
        if(w != null){
            w.dispose();
        }
    }
    
    //create image compatible with monitor
    public BufferedImage createCompatibleImage(int w, int h, int t){
        Window win = getFullScreenWindow();
        if(win != null){
            GraphicsConfiguration gc = win.getGraphicsConfiguration();
            return gc.createCompatibleImage(w,h,t);
        }
        return null;
    }
    
        
    
}
 

Anhänge

  • res2.zip
    32 KB · Aufrufe: 1
Zuletzt bearbeitet:
B

bERt0r

Gast
Ich diese Berechnung des Index erstmal vereinheitlichen und diese ganzen difusen +1 Operationen rausschmeissen:
Java:
if (map_mov[map[(px-movspeed)/32][py/32][0]] == false){
                   move_left = false;
            }
                if(map_mov[map[(px+movspeed)/32][py/32][0]] == false){
                   move_right = false;
            }
            if(map_mov[map[(px)/32][(py-movespeed)/32][0]] == false){
                   move_down = false;
            }
                if(map_mov[map[px/32][(py+movspeed)/32-1][0]] == false){
                   move_up = false;
            }
Wenn du jetzt Kollisionsprobleme hast, würd ich sagen, gib doch einfach mal die errechneten Indexes aus. Wenn du jetzt nämlich das Problem hast, dass bei einer Rechnung 3,1 rauskommt, und das ganze auf 3 gerundet wird, könnte deine Spielfigur in einen verbotenen Bereich laufen.
 

Ariol

Top Contributor
Ok, bei mir ruckelt es zwar ziemlich aber ich denke ich hab den Fehler gefunden:
Java:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
 
import javax.imageio.ImageIO;
import javax.swing.*;
 
public class Main implements KeyListener {  
    
    private static DisplayMode modes[] = {
        new DisplayMode(1024, 768, 32,0),
        new DisplayMode(800, 600, 32,0),
        new DisplayMode(800, 600, 24,0),
        new DisplayMode(800, 600, 16,0),
        new DisplayMode(640, 480, 32,0),
        new DisplayMode(640, 480, 24,0),
        new DisplayMode(640, 480, 16,0),
    };
    
    private boolean running;
    protected ScreenManager s;
    //private Animation a;
    //protected Sprite sprite;
    
    
    
    //tile engine
    ArrayList<BufferedImage> tiles = new ArrayList<BufferedImage>();
    public BufferedImage face;
    public BufferedImage tile;
    public BufferedImage test;
    
    int map_width = 32;
    int map_height = 24;
    
    //map array
    int[][][] map = new int[map_width][map_height][3];
    //collision array
    boolean[] map_mov = new boolean[8];
    //player coll
    boolean move_right;
    boolean move_left;
    boolean move_down;
    boolean move_up;
    
    int px=32;
    int py=32;
    
    //player movement speed
    int movspeed = 4;
    
    String mess = "";
    
    public static void main(String[] args){
        Main c = new Main();
        c.run();
    }
 
    //stop method
    public void stop() {
        running = false;
    }
    
    //call init and gameloop
    public void run() {
        try{
            init();     
            loadImages();
            loadMap();
            gameLoop();
 
        }finally{
            s.restoreScreen();
        }
    }
    
    //set to full screen
    public void init() {
        s = new ScreenManager();
        DisplayMode dm = s.findFirstCompatibleMode(modes);
        s.setFullScreen(dm);
        
        Window w = s.getFullScreenWindow();
        w.setFocusTraversalKeysEnabled(false);
        w.addKeyListener(this);
        w.setFont(new Font("Arial", Font.PLAIN, 20));
        w.setBackground(Color.BLACK);
        w.setForeground(Color.WHITE);
        running = true;
        
        mess = "press escape to exit";
    }
   
    //load images
    public void loadImages(){
 
        try {
            BufferedImage[] ntile = new BufferedImage[8];
            String s = "";
            for(int i=0; i<8; i++){
                s = String.format("gfx/100" + i + ".png");
                ntile[i] = ImageIO.read(new File(s));
                this.tiles.add(ntile[i]);
            }
            
            face = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
            face = ImageIO.read(new File("gfx/face.png"));
 
        }catch (IOException error){
            System.err.println("gfx not found");
            error.printStackTrace();
        }
        
        //face = new ImageIcon("gfx/face.png").getImage();
        
        
    }
    
    public void loadMap(){
        try {
            BufferedInputStream buf=new BufferedInputStream(new FileInputStream("testmap.test"));
            ObjectInputStream read = new ObjectInputStream(buf);
 
            map=(int[][][]) read.readObject();
            String name=(String) read.readObject();
            String fileName=(String) read.readObject();
 
            read.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
        }
        
        map_mov[0] = true;
        map_mov[1] = true;
        map_mov[2] = false;
        map_mov[3] = false;
        map_mov[4] = true;
        map_mov[5] = true;
    }
    
    public void playerMove(){
        
    }
    
    //main gameLoop
    public void gameLoop() {
        long startTime = System.currentTimeMillis();
        long cumTime = startTime;
        
        while(running){
            long timePassed = System.currentTimeMillis() - cumTime;
            cumTime += timePassed;
            
            update(timePassed);
            
            Graphics2D g = s.getGraphics();
            draw(g);
            
            if (move_right && canMoveRight()){
                px+=movspeed;
	         }else if(move_left && canMoveLeft()){
	                px-=movspeed;
	         }else if(move_down && canMoveDown()){
	                py+=movspeed;
	         }else if(move_up && canMoveUp()){
	                py-=movspeed;
	         }
 
            
            g.dispose();
            s.update();
            
            try{
                Thread.sleep(40);
            }catch(Exception ex){}
            
        }
    }
    
    boolean canMoveLeft(){
    	int x = (px-movspeed)/32;
    	int y = (py)/32;
    	int y_1 = (py+16)/32;
        return map_mov[map[x][y][0]] && map_mov[map[x][y_1][0]] && map_mov[map[x+1][y][0]] && map_mov[map[x+1][y_1][0]];
    }
    boolean canMoveRight(){
    	int x = (px+movspeed)/32;
    	int y = (py)/32;
    	int y_1 = (py+16)/32;
        return map_mov[map[x][y][0]] && map_mov[map[x][y_1][0]] && map_mov[map[x+1][y][0]] && map_mov[map[x+1][y_1][0]];
    }
    boolean canMoveUp(){
    	int x = (px)/32;
    	int y = (py-movspeed)/32;
    	int x_1 = (px+16)/32;
        return map_mov[map[x][y][0]] && map_mov[map[x][y+1][0]] && map_mov[map[x_1][y][0]] && map_mov[map[x_1][y+1][0]];
    }
    boolean canMoveDown(){
    	int x = (px)/32;
    	int y = (py+movspeed)/32;
    	int x_1 = (px+16)/32;
        return map_mov[map[x][y][0]] && map_mov[map[x][y+1][0]] && map_mov[map[x_1][y][0]] && map_mov[map[x_1][y+1][0]];
    }
    
    //keyPressed
    public void keyPressed(KeyEvent ke){
        int keyCode = ke.getKeyCode();
        if(keyCode == KeyEvent.VK_ESCAPE){
            stop();   
        }else if(keyCode== KeyEvent.VK_F1){
            
        }else{
            mess = "Pressed : "+KeyEvent.getKeyText(keyCode);
            ke.consume();
        }   
       
                    
        //Tastaturabfrage
        switch (ke.getKeyCode()) {
            case KeyEvent.VK_RIGHT: {
                move_right = true;
                move_left = false;
                move_up = false;
                move_down = false;
            }
            break;
            
            case KeyEvent.VK_LEFT: {     
                move_right = false;
                move_left = true;
                move_up = false;
                move_down = false;
            }
            break;
            
            case KeyEvent.VK_DOWN: {  
                move_right = false;
                move_left = false;
                move_up = false;
                move_down = true;
            }
            break;
             
            case KeyEvent.VK_UP: {
                move_right = false;
                move_left = false;
                move_up = true;
                move_down = false;
            }
            break;
       }
    
    }
    
    
    //keyReleased
    public void keyReleased(KeyEvent e){
        int keyCode = e.getKeyCode();
        mess = "Released : "+KeyEvent.getKeyText(keyCode);
        e.consume();
    }
    
    //last method from interface
    public void keyTyped(KeyEvent e){
        e.consume();
    }
    
    //update animation
    public void update(long timePassed){
        
    }
 
    //draws to screen
    public void draw(Graphics2D g){
        Window w = s.getFullScreenWindow();
        
        g.setColor(w.getBackground());
        g.fillRect(0, 0, s.getWidth(), s.getHeight());
        g.setColor(w.getForeground());
        
    
        
        for(int x=0;x < 31; x++){
            for(int y=0;y < 23;  y++){
                for(int z=0; z<=0; z++){
                    if(map[x][y][z] != 0){              
                        g.drawImage(tiles.get(map[x][y][z]), x*32, y*32,32,32, null);
                    }   
                }
            }
        }   
        
        g.drawImage(face, px, py, null);
        
        //realtime debug
        g.drawString(mess, 30, 30);
        g.drawString(String.format(""+px), 30, 50);
        g.drawString(String.format(""+py), 30, 70);
        //collision
        g.drawString(String.format("PX32: "+(int)((double)px)/32 + "-" + (int)((double)px+32)/32), 250, 30);
        g.drawString(String.format("PY32: "+(int)((double)py)/32 + "-" + (int)((double)py+32)/32), 250, 50);
        if (px/32 != 0 && px/32 != 31){
            g.drawString(String.format("Tile right: "+map[px/32+1][py/32][0]), 380, 30);
            g.drawString(String.format("Tile left: "+map[px/32-1][py/32][0]), 380, 50);
        }
        if (py/32 != 0 && py/32 != 23){
            g.drawString(String.format("Tile up: "+map[px/32][py/32-1][0]), 380, 70);
            g.drawString(String.format("Tile down: "+map[px/32][py/32+1][0]), 380, 90);
        }
    }
    
    
}

Sag' mir ob's so geht :wink:

Das Problem ist, dass die Koordinaten des Spielers immer oben links sind. Wenn man nun zwischen 2 Feldern sitzt, läuft die Figur zur Hälfte in die Wand.
 

JTryn

Mitglied
Leider nicht. Ganz unten in der Karte geht es beispielsweise überhaupt nicht mehr nach rechts und durch die Lücke kommt man ab und an mit einer X-Koordinate von 192 und manchmal 196.
Aber danke für den Versuch :)

@bERt0r:
Wenn ich das so mache, kommen ganz komische Ergebnisse raus. Nach unten will er dann zum
Beispiel überhaupt nicht mehr und nach rechts läuft er weit in die Wand.

Ich frage mich allerdings langsam ob ich mit so einer Kollisionsroutine überhaupt auf dem richtigen
Weg bin und ob das so klappen kann. Alternativ könnte man ja sicherlich auch die Nachsehen ob sich
die Eckpunkte der Grafik mit irgendetwas überschneiden. Aber gibt es keine Möglichkeit das auf diese
Art umzusetzen?
 
B

bERt0r

Gast
Java:
canMoveRight(int px,int py){
int expectedx=(int)Math.floor((px+movspeed)/32);
int expectedy=py;
}
Angenommen deine Figur steht in (24,0). 24+4=28/32=0,875.
Java rundet das jetzt auf 1, die Figur würde da aber gar nicht reinlaufen, weil sie ja immer noch im Tile 0,0 ist. Darum musst du bei rechts immer abrunden (Math.floor()), bei links immer aufrunden (Math.ceil()), bei abwärts auf und bei aufwerts ab.
Dann wird 0,875 auf 0 abgerundet, und die Kollisionsabfrage stimmt.
 
B

bERt0r

Gast
So jetzt ist der Tripple Post komplett sry. Eine weitere Quelle für deine komischen Ergebnisse liegt darin, dass du in deiner KeyEvent handler methode nochmal irgendeine Kollisionsabfrage machst.
Java:
 if (move_left != true && move_right != true || map_mov[map[px/32][py/32+1][0]] != false)
Meiner Meinung nach unnötig, verwirrend und auch falsch. Da hat so eine Abfrage doch nix zu suchen, oder steckt da ein tieferer Sinn dahinter? Du überprüfst bevor du die Figur dann bewegst doch nochmal ob es in diese Richtung erlaubt ist.
 

JTryn

Mitglied
Der Sinn dahinter war die Steuering, wie man sie aus PacMan kennt. Man drückt ein mal
in eine Richtung und dann bewegt sich die Figur bis zur Kollision alleine in diese Richtung.

Ich hab das ganze jetzt mal so eingebaut wie ich es verstanden habe, aber entweder
ist es mittlerweile einfach zu spät für mich oder es läuft immer noch nicht ganz perfekt.

[
Java:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
 
import javax.imageio.ImageIO;
import javax.swing.*;
 
public class Main implements KeyListener {  
    
    private static DisplayMode modes[] = {
        new DisplayMode(1024, 768, 32,0),
        new DisplayMode(800, 600, 32,0),
        new DisplayMode(800, 600, 24,0),
        new DisplayMode(800, 600, 16,0),
        new DisplayMode(640, 480, 32,0),
        new DisplayMode(640, 480, 24,0),
        new DisplayMode(640, 480, 16,0),
    };
    
    private boolean running;
    protected ScreenManager s;
    //private Animation a;
    //protected Sprite sprite;
    
    
    
    //tile engine
    ArrayList<BufferedImage> tiles = new ArrayList<BufferedImage>();
    public BufferedImage face;
    public BufferedImage tile;
    public BufferedImage test;
    
    int map_width = 32;
    int map_height = 24;
    
    //map array
    int[][][] map = new int[map_width][map_height][3];
    //collision array
    boolean[] map_mov = new boolean[8];
    //player coll
    boolean move_right;
    boolean move_left;
    boolean move_down;
    boolean move_up;
    
    int bexpectedx;
    int bexpectedy;
    
    int px=32;
    int py=32;
    
    //player movement speed
    int movspeed = 4;
    
    String mess = "";
    
    public static void main(String[] args){
        Main c = new Main();
        c.run();
    }
 
    //stop method
    public void stop() {
        running = false;
    }
    
    //call init and gameloop
    public void run() {
        try{
            init();     
            loadImages();
            loadMap();
            gameLoop();
 
        }finally{
            s.restoreScreen();
        }
    }
    
    //set to full screen
    public void init() {
        s = new ScreenManager();
        DisplayMode dm = s.findFirstCompatibleMode(modes);
        s.setFullScreen(dm);
        
        Window w = s.getFullScreenWindow();
        w.setFocusTraversalKeysEnabled(false);
        w.addKeyListener(this);
        w.setFont(new Font("Arial", Font.PLAIN, 20));
        w.setBackground(Color.BLACK);
        w.setForeground(Color.WHITE);
        running = true;
        
        mess = "press escape to exit";
    }
   
    //load images
    public void loadImages(){
 
        try {
            BufferedImage[] ntile = new BufferedImage[8];
            String s = "";
            for(int i=0; i<8; i++){
                s = String.format("gfx/100" + i + ".png");
                ntile[i] = ImageIO.read(new File(s));
                this.tiles.add(ntile[i]);
            }
            
            face = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
            face = ImageIO.read(new File("gfx/face.png"));
 
        }catch (IOException error){
            System.err.println("gfx not found");
            error.printStackTrace();
        }
        
        //face = new ImageIcon("gfx/face.png").getImage();
        
        
    }
    
    public void loadMap(){
        try {
            BufferedInputStream buf=new BufferedInputStream(new FileInputStream("testmap.test"));
            ObjectInputStream read = new ObjectInputStream(buf);
 
            map=(int[][][]) read.readObject();
            String name=(String) read.readObject();
            String fileName=(String) read.readObject();
 
            read.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
        }
        
        map_mov[0] = true;
        map_mov[1] = true;
        map_mov[2] = false;
        map_mov[3] = false;
        map_mov[4] = true;
        map_mov[5] = true;
    }
    
    public void playerMove(){
        
    }
    
    //main gameLoop
    public void gameLoop() {
        long startTime = System.currentTimeMillis();
        long cumTime = startTime;
        
        while(running){
            long timePassed = System.currentTimeMillis() - cumTime;
            cumTime += timePassed;
            
            update(timePassed);
            
            Graphics2D g = s.getGraphics();
            draw(g);
            
            if (move_right && canMoveRight(px,py)){
                px+=movspeed;
             }else if(move_left && canMoveLeft(px,py)){
                    px-=movspeed;
             }else if(move_down && canMoveDown(px,py)){
                    py+=movspeed;
             }else if(move_up && canMoveUp(px,py)){
                    py-=movspeed;
             }
 
            
            g.dispose();
            s.update();
            
            try{
                Thread.sleep(40);
            }catch(Exception ex){}
            
        }
    }
    
    boolean canMoveLeft(int px,int py){
    	int expectedx=(int)Math.floor((px-movspeed)/32);
    	int expectedy=py/32;
    	bexpectedx=expectedx;
    	return map_mov[map[expectedx][expectedy][0]];
    }
    boolean canMoveRight(int px,int py){
    	int expectedx=(int)Math.floor((px+movspeed)/32);
    	int expectedy=py/32;
    	bexpectedx=expectedx;
    	return map_mov[map[expectedx][expectedy][0]];
    	}
    boolean canMoveUp(int px,int py){
    	int expectedx=px/32;
    	int expectedy=(int)Math.floor((py-movspeed)/32);
    	bexpectedy=expectedy;
    	return map_mov[map[expectedx][expectedy][0]];
    }
    boolean canMoveDown(int px,int py){
    	int expectedx=px/32;
    	int expectedy=(int)Math.floor((py+movspeed)/32);
    	bexpectedy=expectedy;
    	return map_mov[map[expectedx][expectedy][0]];
    }
    
    //keyPressed
    public void keyPressed(KeyEvent ke){
        int keyCode = ke.getKeyCode();
        if(keyCode == KeyEvent.VK_ESCAPE){
            stop();   
        }else if(keyCode== KeyEvent.VK_F1){
            
        }else{
            mess = "Pressed : "+KeyEvent.getKeyText(keyCode);
            ke.consume();
        }   
       
                    
        //Tastaturabfrage
        switch (ke.getKeyCode()) {
            case KeyEvent.VK_RIGHT: {
                move_right = true;
                move_left = false;
                move_up = false;
                move_down = false;
            }
            break;
            
            case KeyEvent.VK_LEFT: {     
                move_right = false;
                move_left = true;
                move_up = false;
                move_down = false;
            }
            break;
            
            case KeyEvent.VK_DOWN: {  
                move_right = false;
                move_left = false;
                move_up = false;
                move_down = true;
            }
            break;
             
            case KeyEvent.VK_UP: {
                move_right = false;
                move_left = false;
                move_up = true;
                move_down = false;
            }
            break;
       }
    
    }
    
    
    //keyReleased
    public void keyReleased(KeyEvent e){
        int keyCode = e.getKeyCode();
        mess = "Released : "+KeyEvent.getKeyText(keyCode);
        e.consume();
    }
    
    //last method from interface
    public void keyTyped(KeyEvent e){
        e.consume();
    }
    
    //update animation
    public void update(long timePassed){
        
    }
 
    //draws to screen
    public void draw(Graphics2D g){
        Window w = s.getFullScreenWindow();
        
        g.setColor(w.getBackground());
        g.fillRect(0, 0, s.getWidth(), s.getHeight());
        g.setColor(w.getForeground());
        
    
        
        for(int x=0;x < 31; x++){
            for(int y=0;y < 23;  y++){
                for(int z=0; z<=0; z++){
                    if(map[x][y][z] != 0){              
                        g.drawImage(tiles.get(map[x][y][z]), x*32, y*32,32,32, null);
                    }   
                }
            }
        }   
        
        g.drawImage(face, px, py, null);
        
        //realtime debug
        g.drawString(mess, 30, 30);
        g.drawString(String.format(""+px), 30, 50);
        g.drawString(String.format(""+py), 30, 70);
        //collision
        g.drawString(String.format("PX32: "+(int)((double)px)/32 + "-" + (int)((double)px+32)/32), 250, 30);
        g.drawString(String.format("PY32: "+(int)((double)py)/32 + "-" + (int)((double)py+32)/32), 250, 50);
        g.drawString(String.format("expectedx: "+bexpectedx), 250, 70);
        g.drawString(String.format("expectedy: "+bexpectedy), 250, 90);
        if (px/32 != 0 && px/32 != 31){
            g.drawString(String.format("Tile right: "+map[px/32+1][py/32][0]), 380, 30);
            g.drawString(String.format("Tile left: "+map[px/32-1][py/32][0]), 380, 50);
        }
        if (py/32 != 0 && py/32 != 23){
            g.drawString(String.format("Tile up: "+map[px/32][py/32-1][0]), 380, 70);
            g.drawString(String.format("Tile down: "+map[px/32][py/32+1][0]), 380, 90);
        }
    }
    
    
}

Danke für den Support so spät noch !
 

Ariol

Top Contributor
Auf ein Neues.
Bei mir konnte ich jetzt keine Kollision mehr sehen.
Es gab wohl einen Rundungsfehler. Die berechnete rechte und untere Seite muss natürlich einen Pixel kleiner sein. Mit "+31" sollte es jetzt klappen:

Java:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
 
import javax.imageio.ImageIO;
import javax.swing.*;
 
public class Main implements KeyListener {  
    
    private static DisplayMode modes[] = {
        new DisplayMode(1024, 768, 32,0),
        new DisplayMode(800, 600, 32,0),
        new DisplayMode(800, 600, 24,0),
        new DisplayMode(800, 600, 16,0),
        new DisplayMode(640, 480, 32,0),
        new DisplayMode(640, 480, 24,0),
        new DisplayMode(640, 480, 16,0),
    };
    
    private boolean running;
    protected ScreenManager s;
    //private Animation a;
    //protected Sprite sprite;
    
    
    
    //tile engine
    ArrayList<BufferedImage> tiles = new ArrayList<BufferedImage>();
    public BufferedImage face;
    public BufferedImage tile;
    public BufferedImage test;
    
    int map_width = 32;
    int map_height = 24;
    
    //map array
    int[][][] map = new int[map_width][map_height][3];
    //collision array
    boolean[] map_mov = new boolean[8];
    //player coll
    boolean move_right;
    boolean move_left;
    boolean move_down;
    boolean move_up;
    
    int px=32;
    int py=32;
    
    //player movement speed
    int movspeed = 4;
    
    String mess = "";
    
    public static void main(String[] args){
        Main c = new Main();
        c.run();
    }
 
    //stop method
    public void stop() {
        running = false;
    }
    
    //call init and gameloop
    public void run() {
        try{
            init();     
            loadImages();
            loadMap();
            gameLoop();
 
        }finally{
            s.restoreScreen();
        }
    }
    
    //set to full screen
    public void init() {
        s = new ScreenManager();
        DisplayMode dm = s.findFirstCompatibleMode(modes);
        s.setFullScreen(dm);
        
        Window w = s.getFullScreenWindow();
        w.setFocusTraversalKeysEnabled(false);
        w.addKeyListener(this);
        w.setFont(new Font("Arial", Font.PLAIN, 20));
        w.setBackground(Color.BLACK);
        w.setForeground(Color.WHITE);
        running = true;
        
        mess = "press escape to exit";
    }
   
    //load images
    public void loadImages(){
 
        try {
            BufferedImage[] ntile = new BufferedImage[8];
            String s = "";
            for(int i=0; i<8; i++){
                s = String.format("gfx/100" + i + ".png");
                ntile[i] = ImageIO.read(new File(s));
                this.tiles.add(ntile[i]);
            }
            
            face = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
            face = ImageIO.read(new File("gfx/face.png"));
 
        }catch (IOException error){
            System.err.println("gfx not found");
            error.printStackTrace();
        }
        
        //face = new ImageIcon("gfx/face.png").getImage();
        
        
    }
    
    public void loadMap(){
        try {
            BufferedInputStream buf=new BufferedInputStream(new FileInputStream("testmap.test"));
            ObjectInputStream read = new ObjectInputStream(buf);
 
            map=(int[][][]) read.readObject();
            String name=(String) read.readObject();
            String fileName=(String) read.readObject();
 
            read.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
        }
        
        map_mov[0] = true;
        map_mov[1] = true;
        map_mov[2] = false;
        map_mov[3] = false;
        map_mov[4] = true;
        map_mov[5] = true;
    }
    
    public void playerMove(){
        
    }
    
    //main gameLoop
    public void gameLoop() {
        long startTime = System.currentTimeMillis();
        long cumTime = startTime;
        
        while(running){
            long timePassed = System.currentTimeMillis() - cumTime;
            cumTime += timePassed;
            
            update(timePassed);
            
            Graphics2D g = s.getGraphics();
            draw(g);
            
            if (move_right && canMoveRight()){
                px+=movspeed;
	         }else if(move_left && canMoveLeft()){
	                px-=movspeed;
	         }else if(move_down && canMoveDown()){
	                py+=movspeed;
	         }else if(move_up && canMoveUp()){
	                py-=movspeed;
	         }
 
            
            g.dispose();
            s.update();
            
            try{
                Thread.sleep(40);
            }catch(Exception ex){}
            
        }
    }
    
    boolean canMoveLeft(){
    	int x = (px-movspeed)/32;
    	int y = (py)/32;
    	int x_1 = (px+31-movspeed)/32;
    	int y_1 = (py+31)/32;
        return map_mov[map[x][y][0]] && map_mov[map[x][y_1][0]] && map_mov[map[x_1][y][0]] && map_mov[map[x_1][y_1][0]];
    }
    boolean canMoveRight(){
    	int x = (px+movspeed)/32;
    	int y = (py)/32;
    	int x_1 = (px+31+movspeed)/32;
    	int y_1 = (py+31)/32;
        return map_mov[map[x][y][0]] && map_mov[map[x][y_1][0]] && map_mov[map[x_1][y][0]] && map_mov[map[x_1][y_1][0]];
    }
    boolean canMoveUp(){
    	int x = (px)/32;
    	int y = (py-movspeed)/32;
    	int x_1 = (px+31)/32;
    	int y_1 = (py+31-movspeed)/32;
        return map_mov[map[x][y][0]] && map_mov[map[x][y_1][0]] && map_mov[map[x_1][y][0]] && map_mov[map[x_1][y_1][0]];
    }
    boolean canMoveDown(){
    	int x = (px)/32;
    	int y = (py+movspeed)/32;
    	int x_1 = (px+31)/32;
    	int y_1 = (py+31+movspeed)/32;
        return map_mov[map[x][y][0]] && map_mov[map[x][y_1][0]] && map_mov[map[x_1][y][0]] && map_mov[map[x_1][y_1][0]];
    }
    
    //keyPressed
    public void keyPressed(KeyEvent ke){
        int keyCode = ke.getKeyCode();
        if(keyCode == KeyEvent.VK_ESCAPE){
            stop();   
        }else if(keyCode== KeyEvent.VK_F1){
            
        }else{
            mess = "Pressed : "+KeyEvent.getKeyText(keyCode);
            ke.consume();
        }   
       
                    
        //Tastaturabfrage
        switch (ke.getKeyCode()) {
            case KeyEvent.VK_RIGHT: {
            	if(canMoveRight())//Don't change direction when you can't - no stop, when wall
            	{
	                move_right = true;
	                move_left = false;
	                move_up = false;
	                move_down = false;
            	}
            }
            break;
            
            case KeyEvent.VK_LEFT: {     
            	if(canMoveLeft())//Don't change direction when you can't - no stop, when wall
            	{ 
            		move_right = false;
	                move_left = true;
	                move_up = false;
	                move_down = false;
            	}
            }
            break;
            
            case KeyEvent.VK_DOWN: {  
            	if(canMoveDown())//Don't change direction when you can't - no stop, when wall
            	{
            		move_right = false;
	                move_left = false;
	                move_up = false;
	                move_down = true;
            	}
            }
            break;
             
            case KeyEvent.VK_UP: {
            	if(canMoveUp())//Don't change direction when you can't - no stop, when wall
            	{
            		move_right = false;
	                move_left = false;
	                move_up = true;
	                move_down = false;
            	}
            }
            break;
       }
    
    }
    
    
    //keyReleased
    public void keyReleased(KeyEvent e){
        int keyCode = e.getKeyCode();
        mess = "Released : "+KeyEvent.getKeyText(keyCode);
        e.consume();
    }
    
    //last method from interface
    public void keyTyped(KeyEvent e){
        e.consume();
    }
    
    //update animation
    public void update(long timePassed){
        
    }
 
    //draws to screen
    public void draw(Graphics2D g){
        Window w = s.getFullScreenWindow();
        
        g.setColor(w.getBackground());
        g.fillRect(0, 0, s.getWidth(), s.getHeight());
        g.setColor(w.getForeground());
        
    
        
        for(int x=0;x < 31; x++){
            for(int y=0;y < 23;  y++){
                for(int z=0; z<=0; z++){
                    if(map[x][y][z] != 0){              
                        g.drawImage(tiles.get(map[x][y][z]), x*32, y*32,32,32, null);
                    }   
                }
            }
        }   
        
        g.drawImage(face, px, py, null);
        
        //realtime debug
        g.drawString(mess, 30, 30);
        g.drawString(String.format(""+px), 30, 50);
        g.drawString(String.format(""+py), 30, 70);
        //collision
        g.drawString(String.format("PX32: "+(int)((double)px)/32 + "-" + (int)((double)px+32)/32), 250, 30);
        g.drawString(String.format("PY32: "+(int)((double)py)/32 + "-" + (int)((double)py+32)/32), 250, 50);
        if (px/32 != 0 && px/32 != 31){
            g.drawString(String.format("Tile right: "+map[px/32+1][py/32][0]), 380, 30);
            g.drawString(String.format("Tile left: "+map[px/32-1][py/32][0]), 380, 50);
        }
        if (py/32 != 0 && py/32 != 23){
            g.drawString(String.format("Tile up: "+map[px/32][py/32-1][0]), 380, 70);
            g.drawString(String.format("Tile down: "+map[px/32][py/32+1][0]), 380, 90);
        }
    }
    
    
}
 
B

bERt0r

Gast
canMoveRight(int px,int py){
int expectedx=(int)Math.floor((px+movspeed)/32);
int expectedy=(int)Math.floor(py/32);
}

Du musst py auch abrunden, weil wenn der spieler an Position (0,31) ist, und er will jetzt nach rechts, wird gerundet 31/32=0,9irgendwas ->1 und er überprüft Tile(0,1) statt (0,0) wie er sollte.

Bzgl. dieser +31 Rechnerei bin ich skeptisch, da blick ich nicht ganz durch.
 

Marco13

Top Contributor
Statt dieses krampfigen, über den ganzen Code verschmierten /32+31+-((double)-(-(int)4))-Gewurschtels solltest du lieber eine Methode machen, die die RICHTIGEN Koordinaten ausrechnet, z.B.
Code:
private static Point computePlayerIndices(Point playerPosition)
{
    ...
}
und die dann TESTEN, mit px,py = (0,0), (1,1), (30,30), (31,31), (32,32), (33,33), und noch ein paar am äußeren Rand). Wenn das alles funktioniert, kannst du noch die (wenigen) verbleibenden 32's durch eine Konstante "TILE_SIZE" ersetzen, und DANACH kannst du weitersehen, wie du das mit den Kollisionen machst.

Irgendwie habe ich ohnehin die Vermutung, dass die px,py nicht wirklich benötigt werden, weil sie ohnehin überall nur vielfache von 32 sind, aber das müßte man genauer prüfen.
 

Ariol

Top Contributor
Das
Code:
Math.floor()
wird keinen Unterschied machen. Beim Konvertieren von double nach int wird eh abgerundet.

Beispiel:
Java:
	for(double d = 0.0; d <= 2.0; d+=0.1)
	{
		int i = (int)d;
		int j = (int)Math.floor(d);
		System.out.println(d + ": " + i + "," + j + " --> " + (i==j));
	}

Ausgabe:
Code:
0.0: 0,0 --> true
0.1: 0,0 --> true
0.2: 0,0 --> true
0.30000000000000004: 0,0 --> true
0.4: 0,0 --> true
0.5: 0,0 --> true
0.6: 0,0 --> true
0.7: 0,0 --> true
0.7999999999999999: 0,0 --> true
0.8999999999999999: 0,0 --> true
0.9999999999999999: 0,0 --> true
1.0999999999999999: 1,1 --> true
1.2: 1,1 --> true
1.3: 1,1 --> true
1.4000000000000001: 1,1 --> true
1.5000000000000002: 1,1 --> true
1.6000000000000003: 1,1 --> true
1.7000000000000004: 1,1 --> true
1.8000000000000005: 1,1 --> true
1.9000000000000006: 1,1 --> true

Das mit den +31 lässt sich so erklären:
Die Figur ist 32 Pixel breit. Setze ich sie in die linke, obere Ecke, dann belegt sie die Pixelfläche
Code:
((x1,y1),(x2,y2)) = (0,0),(31,31)
und bleibt damit im ersten Block.

Bewege ich die Figur nun um 1 nach rechts
Code:
((1,0),(32,31))
dann kommen wir auch in den Pixel daneben.
Wie man sieht sind die rechte Seite und die untere Seite jeweils ihre gegenüber + 31.

Rechnet man mit diesen Werten bekommt man die korrekten Koordinaten:
Code:
((0,0),(31,31)) -> ((0/32,0/32),(31/32,31/32)) -> ((0,0),(0,0))
Überprüft werden muss jede Kombination aus x1 und x2. In diesem Fall reicht
Code:
map_mov[map[0][0][0]]

Zweites Beispiel:
Code:
((1,63),(32,94)) -> ((1/32,63/32),(32/32,94/32)) -> ((0,1),(1,2))
Geprüft werden müssen hier:
Code:
map_mov[map[0][1][0]]
map_mov[map[0][2][0]]
map_mov[map[1][1][0]]
map_mov[map[1][2][0]]
 

Ariol

Top Contributor
Statt dieses krampfigen, über den ganzen Code verschmierten /32+31+-((double)-(-(int)4))-Gewurschtels solltest du lieber eine Methode machen, die die RICHTIGEN Koordinaten ausrechnet, z.B.
Code:
private static Point computePlayerIndices(Point playerPosition)
{
    ...
}
und die dann TESTEN, mit px,py = (0,0), (1,1), (30,30), (31,31), (32,32), (33,33), und noch ein paar am äußeren Rand). Wenn das alles funktioniert, kannst du noch die (wenigen) verbleibenden 32's durch eine Konstante "TILE_SIZE" ersetzen, und DANACH kannst du weitersehen, wie du das mit den Kollisionen machst.

Das komische +- Gewurstel wird aber auch dabei nicht ausbleiben.

Irgendwie habe ich ohnehin die Vermutung, dass die px,py nicht wirklich benötigt werden, weil sie ohnehin überall nur vielfache von 32 sind, aber das müßte man genauer prüfen.

Da liegt ja mit eines der Hauptprobleme. Die Figur bewegt sich immer 4 Pixel weit, nicht 32.
 

JTryn

Mitglied
Ja, sonst wäre es auch keine flüssige Bewegung. Die Abfrage wär bei 32er Schritten
natürlich um einiges einfacher, aber eine Figur, die im Raster rumhüpft ist eben
mehr als unschön. Aber durch die +4 treten dann eben die Fehler auf.. px und py
braucht man aber trotzdem, da an diesen Stellen die Grafik angezeigt wird.
Vielen Dank, Ariol und natürlich auch an alle anderen, mit deiner Lösung scheint es nämlich
jetzt zu klappen!

Aber ein winziges Problem habe ich noch, das wohl mit dem KeyListener zu tun hat und
mit der windowseigenen Anschlagverzögerung. Hab dazu jetzt schon einiges gesucht und
konnte auch ein paar Beispiele ausmachen in denen dies umgangen wird, indem man
bei den keyReleased events die flags fürs Bewegen wieder auf false setzt.
Leider konnte ich auch nur diese Lösung finden, aber das Problem ist ja, dass ich das
bei meiner "PacMan-Steuerung" nicht machen kann, weil die Figur sich darüber hinaus
bewegen können soll.

Das Problem sieht man z.B. an Lücken, wie im Bild in einem meiner Posts vor mir:
geht man diese Lücke nach oben und hält, sagen wir mal, die linke Pfeiltaste erst zu spät
gedrückt, bewegt sich die Figur erst nach einer Verzögerung nach links.
Wenn man von links kommt und die Taste früh genug gedrückt hält passiert das nicht,
deswegen vermute ich, dass es an der Anschlagverzögerung liegt.
Wie bekomme ich die unter meinen Bedingungen also 'weg'?

Und zur Kollisionsabfrage noch einmal... ich denke, dass die hier von Grund auf nicht unbedingt
die beste Idee war, das Abfragen einer Art 'Kollisionsbox' wäre wohl intelligenter gewesen, wenn
man dann einfach überprüft ob sich die einzelnen Eckpunkte (2 pro Ecke) von dieser mit
etwas unpassierbarem überschneiden. Dann hätte man sicher nicht solche Probleme mit der Kollision,
wenn man sich um einzelne Pixel bewegt.
 

Ariol

Top Contributor
Versuchs mal so, dann liegen das Zeichnen und das Bewegen der Figur näher beieinander.

Java:
    //main gameLoop
    public void gameLoop() {
        long startTime = System.currentTimeMillis();
        long cumTime = startTime;
        
        while(running){
            long timePassed = System.currentTimeMillis() - cumTime;
            cumTime += timePassed;
            
            update(timePassed);
            
            if (move_right && canMoveRight()){
                px+=movspeed;
             }else if(move_left && canMoveLeft()){
                    px-=movspeed;
             }else if(move_down && canMoveDown()){
                    py+=movspeed;
             }else if(move_up && canMoveUp()){
                    py-=movspeed;
             }
 
            Graphics2D g = s.getGraphics();
            draw(g);
            g.dispose();
            s.update();
            
            try{
                Thread.sleep(40);
            }catch(Exception ex){}
            
        }
    }
 

JTryn

Mitglied
Leider bleibt dabei die Verzögerung.

Um das ganze genauer zu schildern: Das macht es auch unheimlich schwer durch dine Lücke
zu kommen, die neben dem Spieler ist, in diesem Fall muss man z.B. ewig hin und herlaufen
bis man genau die Stelle erwischt, wo er durchkann. Hätte man die Verzögerung nicht, könnte
man einfach die Taste gedrückt halten und würde durchkommen (alles wie beim klassischen
PacMan eben).
 

Ariol

Top Contributor
Sieht die Behandlung von KeyEvents bei dir auch so aus?
Java:
 case KeyEvent.VK_UP: {
                if(canMoveUp())//Don't change direction when you can't - no stop, when wall
                {
                    move_right = false;
                    move_left = false;
                    move_up = true;
                    move_down = false;
                }
            }

Falls nicht solltest du dir evtl. das hier noch einmal ansehen.
Up
Damit hat es gestern bei mir eigentlich durch gedrückt halten geklappt.
 

JTryn

Mitglied
Ja, das mit dem gedrückt halten klappt auch, aber eben nur, wenn man die Taste früh genug,
also weit vor der Lücke schon runterdrückt. Macht man es zu spät, wird das heruntergehen
komplett ignoriert - deswegen vermute ich, dass die Anschlagverzögerung von Windows
damit zu tun hat. Die müsste man eben irgendwie wegbekommen...
 

JTryn

Mitglied
Keiner eine Idee? Finde dazu wirklich gar nichts, außer eben die Problembehebung, dass man
den KeyListener wieder 'freigeben' muss, indem man bei KeyReleased die flags zur Bewegung
wieder auf false setzt. Das würde problemlos klappen, wenn ich nicht diese PacMan-Steuerung
wollen würde. Würde ich es hier auf false setzen bleibt sie eben stehen...
 
B

bERt0r

Gast
Wenn du das ganze so gemacht hast wie ariol in seinem vorletzen post geschrieben hat, dürfte das doch gar nicht auftreten.
Du könntest das ganze auch ein wenig anders aufziehen:
Du merkst dir eine Variable movement_direction, die 4 Zustände erreichen kann (links,rechts,rauf,runter) und änderst die nur, wenn wenn z.b move_right und canMoveRight() true sind.

Wenn du jetzt so ein level hast:
_________________________| |_____
_o_____________________________

und du auf der Position, wo das o jetzt steht 1 mal nach rechts, dann 1 mal nach oben drückst und dann nix mehr, sollte die Figur durch die Öffnung nach oben gehen.
 

Ähnliche Java Themen

Neue Themen


Oben