Desenv. Games: Mover cenário junto com o personagem

Gostaria de um help referente ao desenvolvimento de jogos:

Tenho um cenário jpg que serve como background de uma fase. Esse background é do tamanho do Jframe do jogo. Consigo movimentar o boneco perfeitamente por esse cenário. Mas a dúvida é: Quando o cenário for maior que o jframe, como movimentar o cenario a medida que o boneco avançar, como acontece nos jogos de plataforma? Naturalmente sem scrolls

grato

acredito que nisso posso ajudar…
o problema é q vc como a maioria dos gamers pensa que o personagem gira em torno do mundo…
o negocio é q o mundo gira em torno do personagem…
em outras palavras…
o personagem fica parado na tela e o mundo gira ao redor dele…
mova o mapa e não o personagem.

para mudar o mapa acredito q varia de programação, mas a maioria é só destinar 1 tamanho para tela (frame) e o posicionamento da imagem( x, y)

se puder falar qual linguagem ajuda, e muito…

existem jogos que o cenario fica parado e os personagens se movimentam

É exatamente o que o nebster falou.

É em java SE.
.
Para java ME eu sei que tem o LayerManager para controlar o View Window
http://java.sun.com/javame/reference/apis/jsr118/javax/microedition/lcdui/game/LayerManager.html

Gostaria de saber se tem algo paracido no javase. Ou como vc implementa isso?
Você recomendou mover diretamente o mapa, bom é exatamente isso que eu quero saber como se faz.

grato

Você pode usar o método draw do Graphics2D que desenha apenas parte do BufferedImage.
Aí o resto é só fazer conta.

As posições da imagem serão:

x = Math.min(fundo.getWidth() - tela.getWidth(), Math.max(0, personagem.x - fundo.getWidth() / 2)); y = Math.min(fundo.getHeight() - tela.getHeight(), Math.max(0, personagem.x - fundo.getWidth() / 2));

Onde tela é o tamanho da área visível, fundo é o tamanho total da imagem de fundo e personagem é a posição do seu player.

Bom acho que achei a resposta, na verdade algo absurdamente simples !!
usando valores negativos de forma incremental no drawImage de Graphics

Vejam o código

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package testesjogos;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

/**
 *
 * @author root
 */
public class Cenario extends JFrame {
    public Cenario(){
        setSize(800, 600);
        setResizable(false);        
        setExtendedState(MAXIMIZED_BOTH);  
        setTitle("Teste cenário");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    @Override
    public void paint(Graphics g) {
        BufferedImage image = null;
        try {
            image = ImageIO.read(new File("/home/gustavo/foto.jpg"));
            //g.drawImage(image, 1, 1, null); //posição inicial

            //aqui desloco 400px para direita, se o boneco estivese no meio da tela, 
            //criaria a ilusão de ele ter avançado no cenario em relação do drawimage anterior
            g.drawImage(image, -400, 1, null);
        } catch (IOException e) {
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        Cenario cen = new Cenario();
        cen.setVisible(true);
    }
}

Claro que devo separar o estado do jogo da pintura, mas acho que é por aí.

Conhecem uma maneira mais correta de se fazer isso?

Sim.

O ideal é criar uma classe para controlar o Rendering na tela (você pode chama-la de Renderer).
Essa classe, conhece a posição da câmera. E é ela a responsável por desenhar todas as coisas da tela em relação a essa posição, e restringir a movimentação da câmera.
Ela acaba sendo um wrapper para o objeto Graphics.

Todas as coisas são desenhadas da seguinte forma:
x = posicao_da_coisa.x - posicao_da_camera.x
y = posicao_da_coisa.y - posicao_da_camera.y

A grande vantagem de ter uma classe assim, é que tudo pode ser desenhado na posição que você imagina o cenário completo. Para que a câmera siga o personagem, basta a cada gameloop você definir a posição da câmera para a posição do personagem.

Não entendi muito bem o rendering,
Mas a animação de que eu estava falando é mais ou menos esta:

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

/**
 * Desloca imagem para direita
 * @author root
 */
public class DeslocarImagem extends JFrame implements Runnable {

    private BufferedImage img = null;
    private int currentPos = 1;

    public DeslocarImagem() {
        //carrega a imagem no construtor
        try {
            //essa imagem precisa ter mais de 300 de largura para ser percorrida pelo frame
            img = ImageIO.read(new File("/home/gustavo/fotos/1.jpg"));
        } catch (IOException ex) {
            Logger.getLogger(DeslocarImagem.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        setSize(300, 300);
        setResizable(false);
        setExtendedState(MAXIMIZED_BOTH);
        setTitle("Teste cenário");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            repaint();
            //aqui forço para andar para frente como se a sete para direita estivese precionada, mas pode-se aqui capturar key events e então se
           //seta para direita decrementa, se esquerda incrementa
            currentPos = currentPos - 10;
            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                Logger.getLogger(AnimarImagens.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(img, currentPos, 1, null);
    }

    public static void main(String[] args) {        
        DeslocarImagem d = new DeslocarImagem();
        d.setVisible(true);
        d.run();
    }
}

Naturalmente precisa refatorar esse código.
Ao executarem imaginem um boneco correndo no meio da tela eheheh

obrigado pela ajuda

É meio demorado explicar como organizar esse código pelo GUJ. E ultimamente estou meio sem tempo para montar um exemplo decente.
Mas seria bom você organizar diversas coisas, como seu loop de animação, usar desenho direto, etc.

Dê uma olhada nos tutoriais de Java do Ponto V:
http://pontov.com.br/site/java/47-javageral
http://pontov.com.br/site/java/48-java2d

Ou em pouco tempo você terá um jogo pouco fluído e piscando.

Outra alternativa é usar uma plataforma que seja mais adequada para jogos, como C# + XNA, SDL ou mesmo a Unity.
Infelizmente, o J2SE é carente em muitas coisas, como sons, por exemplo.

Olá, fiz um pequeno framework com base nas dicas fornecidas.
Ele controla por si mesmo o game loop, bufferstrategy, bind de keylistners etc

Para fazer um jogo basta implementar esta interface:

import java.awt.Graphics;

/**
 *
 * @author root
 */
public interface Game {
    
    /*
     * Inicia o game, splashscreen, carregas as imagens etc.
     */
    public void initGame();
    
    /*
     * Processa tecla pressionada
     */
    public void processGameKeyPressed(int key); 
    
    /*
     * Processa tecla solta
     */
    public void processGameKeyReleased(int key); 
    
    /*
     * Atualiza lógica do game
     */
    public void updateGameLogic();
    
    /*
     * Renderiza o game utilizando aqui o graphics fornecido pelo framework atravez de bufferstrategy. 
     * Antes de executar este método, o framework também já limpa o frame anterior.
     * A área deste graphis já desconta os Insets do jframe. o framework também da o dispose automaticamente no final do uso.
     */
    public void renderGame(Graphics g); 
    
    /*
     * Finaliza o game, tela de gameover etc.
     */
    public void endGame();
    
    /*
     * Este método controla a continuidade do game loop, que é controlado pelo framework
     */
    public boolean continueGame();
}

e então passar a implementação para o framework:

GameLoader.load(Game game);

Segue um exemplo. Neste jogo podemos movimentar um personagem pela tela, apenas como exemplo. Percebam que o código só tem a lógica do jogo. Toda a parte de controle do loop, bufferstrategy, jframe etc. etc. está encapsulada no framework

import gameframework.Game;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;

/**
 *
 * @author root
 */
public class Jogo implements Game{
    private boolean rodando = true;
    private int x = 0;
    private int y = 0;
    private BufferedImage boneco = null;

    @Override
    public void initGame() {
        try {
            boneco = ImageIO.read(new File("/home/gustavo/images/boneco.png"));//coloque aqui a imagem pequena que tiver em seu PC.             
        } catch (IOException ex) {}
        JOptionPane.showMessageDialog(null, "Movimente usando setas do teclado. 'Esc' para sair");//splashscreen
    }

    @Override
    public void processGameKeyPressed(int key) {
        if(key == KeyEvent.VK_ESCAPE){
            rodando = false;//sai do jogo
        }
        if(key == KeyEvent.VK_RIGHT){
            x = x + 2;
        }
        if(key == KeyEvent.VK_LEFT){
            x = x - 2;
        }
        if(key == KeyEvent.VK_UP){
            y = y - 2;
        }
        if(key == KeyEvent.VK_DOWN){
            y = y + 2;
        }
    }

    @Override
    public void processGameKeyReleased(int key) {}

    @Override
    public void updateGameLogic() {}

    @Override
    public void renderGame(Graphics g) {
        g.drawImage(boneco, x, y, null);
    }

    @Override
    public void endGame() {
        JOptionPane.showMessageDialog(null, "Game Over");
    }

    @Override
    public boolean continueGame() {
        return rodando;
    }
}

E então para iniciar o jogo:

public static void main(String[] args) {
        // TODO code application logic here
        Jogo jogo = new Jogo();
        GameLoader.load(jogo);
    }

Naturalmente ele está muito aberto, não define por exemplo interface de sprite e então, recursivamente, atualiza a lógica de cada sprite e o pinta na tela.
Fica para uma próxima versão

Minha dúvida agora é outra, embora relacionada ao mesmo tópico como o assunto é outro abri este tópico:

http://guj.com.br/java/264751-desenv-games-sons-simultaneos

Eis a versão final do meu jogo: https://sites.google.com/site/asteroidsrain/
Baixe na pagina ‘download’

Até que ficou legal.
Grato pela ajuda

ficou legal sim mano, de vez em quando trava um pouco, mas eu acho que você poderia desenvolver uma versão android e quem sabe ganhar algun dinheiro, é assim tão diferente programar pra android?

Oi Elisson, obrigado pela dica.

Continuo esta conversa (com este novo assunto que você levantou) neste outro topico:
http://www.guj.com.br/java/279951-game-asteroidsrain-jogo-em-java-2d

att