[Resolvido]Utilizando scripts para desenhar

Fala galera, depois de um bom tempo distraido com faculdade e principalmente, dota :smiley: , finalmente reiniciei a programação do meu software CG em Java, o UniversoPessoal. Nessa nova versão, estou implementado um sistema de script, que vai usar python.

Me embananei um pouco mas já consegui implementar o Jython e tals, o problema é que no meu programa estou deixando uma linha de comando a principio, pro cara fazer ações simples mesmo. Já criei uma série de comandos simples, que possibilitam fazer as mesmas ações que são feitas com mouse.

Aqui aparece o primeiro problema: eu quero ter a opção de, quando eu apertar seta pra cima, o campo(JtextField) se preencha com último comando que eu digitei. Se eu apertar de novo, que apareça o anterior, e assim por diante. Se eu apertar pra baixo, voltaria os comandos posteriores, que nem numa linha de comando comum como no linux ou no prompt do windows. O problema é que usando action listenner, num sei se isso é possível. Mas por acaso tem outro jeito simples de fazer isso? Minha preocupação é só a interface, porque salvar o que usuário digitar eu sei fazer.

Ai vem o segundo problema. Pra num deixar uma coisa totalmente chata, resolvi criar um script em python mesmo que simularia um jogo de corrida no programa. Desenhar uma pista foi simples, o ruim é fazer com que ela se anime. Tentei usar o código abaixo, mas acontece que o programa inteiro roda e só final exibe o resultado, alguém sabe se eu tenho que usar trheads pra isso funcionar? Ou eu tenho que dar um jetio de usar invoker later e etc no meu action performed?
Eis o código:

/**
 * Arquivo onde é armazenado o interpretador de scripts do programa
 */
package br.ericware.programa;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/** Classe responsável por executar todo e qualquer script necessário para execução do programa
 * @author elisson
 *
 */
public class Interpretador implements ActionListener{

	/**
	 * Armazena o módulo 2D
	 */
	private Mod2D mod2D;

	/**
	 * Armazena o desenhista, por onde os desenhos são feitos
	 */
	private Desenhista desenhista;

	/**
	 * Cria a conexão com o interpretador Python
	 */
	private ScriptEngine engine = new ScriptEngineManager().getEngineByName("python");;

	/**
	 * Construtor que recebe como parâmetro o móludo de desenho e o desenhista
	 * @param m2d o módulo2D de onde virão os scripts
	 * @param ds o desenhista do módulo em questão
	 */
	public Interpretador(Mod2D m2d, Desenhista ds) {
		this.mod2D = m2d;
		this.desenhista = ds;
		try {
			engine.eval("from " + Executor.class.getPackage().getName() + " import "+ Executor.class.getSimpleName());

			Set<Class> classes = new HashSet<Class>();

			for (Method metodo : Executor.class.getMethods()) {
				if(Modifier.isPublic( metodo.getModifiers())){
					if(metodo.getName() != "brincar"){
						classes.addAll(Arrays.asList(metodo.getParameterTypes()));
						classes.add(metodo.getReturnType());
						StringBuffer sb =  new StringBuffer("def "+ metodo.getName()+"(");
						for(int i = 0; i < metodo.getParameterTypes().length;i++){
							if(i > 0)
								sb.append(",");
							sb.append("param" + i);

						}
						sb.append("):");
						StringBuffer chamada = new StringBuffer("return "+Executor.class.getSimpleName()+"."+metodo.getName()+"(");
						for(int i = 0; i < metodo.getParameterTypes().length;i++){
							if(i > 0)
								chamada.append(",");
							chamada.append("param" + i);
						}
						chamada.append(")");
						engine.eval(sb.toString()+"\n   "+chamada.toString());
					}else{
						StringBuffer jogo = new StringBuffer("from time import time" +
								"\nvezes = 0" +
								"\ndef brincar():" +
								"\n   global vezes"+
								"\n   comeco = time()" +
								"\n   while(vezes< 6000):" +
								"\n      if((comeco - time()/1000)> 1.5):" +
								"\n         deslocaPista()" +
								"\n         comeco = time()" +
								"\ndef deslocaPista():"+
								"\n   global vezes"+
								"\n   soma = ((vezes%4)*30)" +
								"\n   alterarCorPrimaria(Color.black)" +
								"\n   desenharRetangulo(Point(0,0),Point(400,400))" +
								"\n   alterarCorPrimaria(Color.white)" +
								"\n   desenharRetangulo(Point(185,(-130)+soma),Point(215,(-40)+soma))" +
								"\n   desenharRetangulo(Point(185,0+soma),Point(215,90+soma))" +
								"\n   desenharRetangulo(Point(185,110+soma),Point(215,200+soma))" +
								"\n   desenharRetangulo(Point(185,220+soma),Point(215,310+soma))" +
						"\n   vezes= vezes+1" );
						engine.eval(jogo.toString());
					}
				}
			}
			for(Class classe :classes){
				if(!classe.isPrimitive()){
					engine.eval("from " + classe.getPackage().getName() + " import "+ classe.getSimpleName());
				}
			}
		} catch (ScriptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub

		JTextField linhaComando =  (JTextField) e.getSource();
		try {
			engine.eval(linhaComando.getText());
		} catch (ScriptException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		linhaComando.setText("");
	}

}

Aqui está a classe Executor

[code]
/**

  • Armazena classe responsável pela execução de comandos para o programa
    */
    package br.ericware.programa;

import java.awt.Color;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;

import javax.swing.AbstractButton;
import javax.swing.ButtonModel;

import org.python.antlr.base.mod;

import br.ericware.desenhos.Elipse;
import br.ericware.desenhos.Linha;
import br.ericware.desenhos.Poligono;
import br.ericware.desenhos.Retangulo;
import br.ericware.desenhos.Texto;
import br.ericware.programa.Desenhista.EstadoSelecao;
import br.ericware.programa.Mod2D.NaoSalvouException;

/**Classe responsável por executar os comandos repassados ao programa, não importando a origem
*

  • @author elisson

*/
public class Executor {

/**
 * Armazena a instância única do mod2d para realizar as operações
 */
private static Mod2D mod2d;

/**
 * Armazena a instância desenhista ligada a instancia de Mod2D armazenada
 */
private static Desenhista ds;

/**
 * Determina qual instância será usada para as operações
 * @param m2 a instância que será usada para as operações
 */
static void setMod2D(Mod2D m2){
	Executor.mod2d = m2;
}

/**Determina a instância de Desenhista ligado a instância de mod2d armazenada
 * @param ds o desenhista que deseja-se armazenar
 */
static void setDs(Desenhista ds) {
	Executor.ds = ds;
}

/**
 * Abre uma imagem a partir do arquivo indicado
 * @param arquivo caminho do arquivo para abrir a imagem
 */
public static void abrirImagem(String arquivo){
	mod2d.giGerenciador.abreImagem(arquivo);
}

/**
 * Abre uma imagem a partir do caminho indicado pelo objeto
 * @param arquivo a instância que apontar para o local onde o caminho está
 */
public static void abrirImagem(File arquivo) {
	mod2d.giGerenciador.abreImagem(arquivo);
}

/**
 * Cria uma nova imagem nas dimensões padrões
 */
public static void criarImagem() {
	mod2d.giGerenciador.novaImagem();
}

/**
 * Fecha a imagem indicada
 * @param img a imagem que se deseja para de editar
 */
public static void fecharImagem(Imagem img) {
	mudarImagemEmFoco(img);
	mod2d.giGerenciador.fechaImagemAtual();
}

/**
 * Fecha a imagem atual
 */
public static void fecharImagemAtual() {
	mod2d.giGerenciador.fechaImagemAtual();
}

/**
 * Altera a imagem em foco para imagem indicada
 * @param novaImagem a imagem que se desejar focar
 */
public static void mudarImagemEmFoco(Imagem novaImagem) {		
	mod2d.giGerenciador.modificaImagemFocada(mod2d.giGerenciador.getLsImagens().indexOf(novaImagem));
	
}

/**
 * Altera a resolução da imagem atual para a indicada
 * @param novaAltura a nova altura da imagem
 * @param novaLargura a nova largura da imagem
 */
public static void alterarResolucao(int novaAltura,int novaLargura){
	mod2d.giGerenciador.getImagemAtual().getDesfazerRefazer().addEdit(new AcaoImagem(mod2d.giGerenciador,ds,mod2d.giGerenciador.getImagemAtual(), novaLargura/(float)mod2d.giGerenciador.getImagemAtual().getTamanho().width, novaAltura/(float)mod2d.giGerenciador.getImagemAtual().getTamanho().height));
	mod2d.giGerenciador.getImagemAtual().setTamanho(novaLargura, novaAltura);
	mod2d.giGerenciador.atualizaTitulo();
	ds.invalidar();
	
}

/**
 * Altera o nome da imagem atual
 * @param nome o novo nome que se deseja dar a imagem atual
 */
public static void alterarNome(String nome){
	mod2d.giGerenciador.getImagemAtual().setNome(nome);
	mod2d.giGerenciador.atualizaTitulo();
}

/**
 * Salva a iamgem indicada
 * @param img a imagem que se deseja salvar
 */
public static void salvarImagem(Imagem img){
	mod2d.giGerenciador.modificaImagemFocada(mod2d.giGerenciador.getLsImagens().indexOf(img));
	try {
		mod2d.giGerenciador.salvarImagemAtual();
	} catch (IOException ioe) {
		// TODO Auto-generated catch block
		ioe.printStackTrace();
	} catch (NaoSalvouException nse) {
		nse.printStackTrace();
	}
}

/**
 * Salva a imagem indicada com o nome indicado
 * @param img a imagem que se deseja salvar
 * @param arquivo o caminho para o arquivo onde deseja-se salvar a imagem
 */
public static void salvarImagem(Imagem img, String arquivo){
	mod2d.giGerenciador.modificaImagemFocada(mod2d.giGerenciador.getLsImagens().indexOf(img));
	try {
		mod2d.giGerenciador.salvarImagemAtual(new File(arquivo));
	} catch (IOException ioe) {
		// TODO Auto-generated catch block
		ioe.printStackTrace();
	} catch (NaoSalvouException nse) {
		nse.printStackTrace();
	}
}

/**
 * Retorna a imagem atual
 * @return a imagem atual
 */
public static Imagem retornarImagemAtual(){
	return mod2d.giGerenciador.getImagemAtual();
}

/**
 * Fecha o programa
 */
public static void fecharPrograma(){
	try {
		mod2d.fecha();
	} catch (NaoSalvouException nse) {
		// TODO Auto-generated catch block
		nse.printStackTrace();
	}
}

/**
 * Copia a parte da imagem indicada pelo retangulo
 * @param retangulo o retangulo da onde a imagem será copiada
 */
public static void copiar(Rectangle retangulo){
	Executor.criarSelecao(retangulo);
	mod2d.transfer.copiar(ds);
}

/**
 * Colar uma imagem da área de transferencia na área indicada
 * @param retangulo o retangulo onde a imagem será colada
 * @param img a imagem que será colada na área indicada
 */
public static void colar(Rectangle retangulo, Image	img){
	Executor.criarSelecao(retangulo);
	try {
		mod2d.transfer.colar(ds);
	} catch (UnsupportedFlavorException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}

/**
 * Extrai uma imagem da área indicada
 * @param retangulo a área da onde a imagem será extraída
 */
public static void recortar(Rectangle retangulo){
	Executor.criarSelecao(retangulo);
	mod2d.transfer.recortar(ds);
}

/**
 * Altera a cor primária atual para a cor indicada
 * @param novaCor a nova cor que será aplicada
 */
public static void alterarCorPrimaria(Color novaCor){
	mod2d.setCorPrimaria(novaCor);
}

/**
 * Altera a cor secundária atual para a cor indicada
 * @param novaCor a nova cor que será aplicada
 */
public static void alterarCorSecundaria(Color novaCor){
	mod2d.setCorSecundaria(novaCor);
}

/**
 * Desenha uma linha entre os pontos indicados
 * @param origem ponto de origem da linha
 * @param fim ponto de fim da linha
 */
public static void desenharLinha(Point origem, Point fim){
	Linha linha = new Linha(origem.x, origem.y, ds.getCorPrimaria());
	linha.setFimX(fim.x).setFimY(fim.y);
	linha.setEspessuraLinha((float) mod2d.getEspessuraAtual());
	mod2d.giGerenciador.getImagemAtual().getLsDesenhosPendentes().add(linha);
	ds.finalizaUltimoDesenho();
	ds.repaint();
}

/**
 * Desenha a elipse tendo como limites os pontos indicados
 * @param origem um dos pontos que marcará o limite da elipse
 * @param fim outro ponto que marcará o limite da elipse
 */
public static void desenharElipse(Point origem, Point fim){
	Elipse elipse = new Elipse(origem.x, origem.y,fim.x,fim.y, ds.getCorPrimaria());
	elipse.setEspessuraLinha((float) mod2d.getEspessuraAtual());
	mod2d.giGerenciador.getImagemAtual().getLsDesenhosPendentes().add(elipse);
	ds.finalizaUltimoDesenho();
	ds.repaint();
}

/**
 * Cria um circulo a partir do seu centro e raio
 * @param centro ponto que ser o centro do círculo
 * @param raio distancia do centro até a borda do circulo
 */
public static void desenharCirculo(Point centro, int raio){
	Elipse circulo = new Elipse(centro.x -raio, centro.y - raio,centro.x+raio,centro.y+raio, ds.getCorPrimaria());
	circulo.setEspessuraLinha((float) mod2d.getEspessuraAtual());
	mod2d.giGerenciador.getImagemAtual().getLsDesenhosPendentes().add(circulo);
	ds.finalizaUltimoDesenho();
	ds.repaint();
}

/**
 * Desenha um retangulo limitado pelos pontos indicados
 * @param origem um ponto que limitará o retângulo
 * @param fim outro ponto que limitará o retângulo
 */
public static void desenharRetangulo(Point origem, Point fim){
	Retangulo retangulo = new Retangulo(origem.x, origem.y,fim.x,fim.y, ds.getCorPrimaria());
	retangulo.setEspessuraLinha((float) mod2d.getEspessuraAtual());
	mod2d.giGerenciador.getImagemAtual().getLsDesenhosPendentes().add(retangulo);
	ds.finalizaUltimoDesenho();
	ds.repaint();
}

/**
 * Cria um texto a partir do ponto indicado
 * @param origem o ponto que será o canto inferior esquerdo do texto
 */
public static void inserirTexto(Point origem){
	Texto texto = new Texto(origem.x, origem.y, mod2d.clCorPrimaria, mod2d.jfJanela, ds);
	mod2d.giGerenciador.getImagemAtual().getLsDesenhosPendentes().add(texto);
}

/**
 * Cria um texto a partir do texto e ponto indicados
 * @param origem o ponto onde o texto iniciará
 * @param texto o texto que será impresso
 */
public static void inserirTexto(Point origem, String texto){
	Texto textoImpresso = new Texto(origem.x, origem.y, mod2d.clCorPrimaria, mod2d.jfJanela, ds,texto);
	mod2d.giGerenciador.getImagemAtual().getLsDesenhosPendentes().add(textoImpresso);
	ds.finalizaUltimoDesenho();
}

/**
 * Indica uma área que será preenchida pela cor de fundo
 * @param retanguloApagado o retangulo que será pagado
 */
public static void apagarArea(Rectangle retanguloApagado){
	Retangulo retangulo = new Retangulo(retanguloApagado.x, retanguloApagado.y,retanguloApagado.x+retanguloApagado.width,retanguloApagado.y+retanguloApagado.height, mod2d.clCorSecundaria);
	retangulo.setEspessuraLinha((float) mod2d.getEspessuraAtual());
	mod2d.giGerenciador.getImagemAtual().getLsDesenhosPendentes().add(retangulo);
	ds.finalizaUltimoDesenho();
	ds.repaint();
}

/**
 * Aplica a ferramenta lata de tinta no ponto indicado
 * @param ponto o ponto que se deseja preencher os arredores
 */
public static void preencherPonto(Point ponto){
	Poligono preenchimento = ds.geraPoligonoPreenchido(ponto.x,ponto.y,ds.getImagem());
	mod2d.giGerenciador.getImagemAtual().getLsDesenhosPendentes().add(preenchimento);
	ds.finalizaUltimoDesenho();
	ds.repaint();
}

/**
 * Cria um novo polígono a partir do ponto indicado
 * @param origem o ponto que será a origem do polígono
 */
public static void iniciarPoligono(Point origem){
ds.verificaInicioPoligono(origem.x, origem.y);	
}

/**
 * Continua a traçar o polígono até o ponto indicado
 * @param destino o ponto da onde será traçado uma linha que alcançará o atual fim do poligono
 */
public static void extenderPoligono(Point destino){
	ds.verificaInicioPoligono(destino.x, destino.y);	
}

/**
 * Finaliza o poligno no ponto indicado
 * @param destino o ultimo ponto do poligono que se deseja traçar
 */
public static void finalizarPoligono(Point destino){
	ds.verificaInicioPoligono(destino.x, destino.y);
	finalizarPoligono();
}

/**
 * Finaliza o poligono que está sendo desenhado
 */
public static void finalizarPoligono(){
	ds.finalizaUltimoDesenho();
	ds.repaint();
}

/**
 * Amostra a cor no ponto indicado
 * @param ponto o ponto da onde se deseja tirar a cor primária
 */
public static void amostrarCor(Point ponto){
	ds.amostraCor((int)(ponto.x*mod2d.giGerenciador.getImagemAtual().getZoom()),(int)(ponto.y*mod2d.giGerenciador.getImagemAtual().getZoom()));
}

/**
 * Aumenta o zoom
 */
public static void aumentarZoom(){
	ds.aumentaZoom();
}

/**
 * Diminui o zoom
 */
public static void diminuirZoom(){
	ds.diminuiZoom();
}

/**
 * Determina o zoom
 * @param zoom O valor em porcentagem qeu se deseja para o novo zoom
 */
public static void aplicarZoom(int zoom){
	ds.setZoom(((double)(zoom))/100.0);
}

/**
 * Altera a espessura da ferramenta atual
 * @param espessura a nova espessura desejada
 */
public static void alterarExpessura(double espessura){
	mod2d.setEspessuraAtual(espessura);
}

/**
 * Troca a ferramenta atualmente usada pela indicada por seu nome
 * @param ferramenta o nome da ferramenta desejada
 */
public static void trocarFerramenta(String ferramenta){
	Enumeration<AbstractButton> botoes = mod2d.bgFerramentas.getElements();
	while(botoes.hasMoreElements()){
		AbstractButton botao = botoes.nextElement();
		if(botao.getName() == ferramenta){
			ButtonModel modelo = botao.getModel();
			mod2d.bgFerramentas.setSelected(modelo, true);
		}
	}
}

/**
 * Inicia um joguinho de corrida :)
 */
public static void brincar(){
	
}

/**
 * Rotaciona a imagem no sentido horário
 */
public static void rotacionar(){
	mod2d.giGerenciador.getImagemAtual().rotacionar();
}

/**
 * Desfaz a última ação realizada na imagem atual
 */
public static void desfazer(){
	if(mod2d.giGerenciador.getImagemAtual().getDesfazerRefazer().canUndo())
		mod2d.giGerenciador.getImagemAtual().getDesfazerRefazer().undo();
}

/**
 * Refaz a última ação desfeita na imagem
 */
public static void refazer(){
	if(mod2d.giGerenciador.getImagemAtual().getDesfazerRefazer().canRedo()){
		mod2d.giGerenciador.getImagemAtual().getDesfazerRefazer().redo();
	}
}

/**
 * Cria uma seleção na área do retangulo indicado. Entretano, a seleção só será exibida se a ferramenta seleciona for seleção
 * @param area o retangulo onde ficará a seleção
 */
public static void criarSelecao(Rectangle area){
	mod2d.setSelecao(area);
}

}[/code]
Uma ajuda pra qualquer um dos problema é muito bem vinda, Agradeço desde já.

Eu tive muito menos problemas com o Groovy, por isso acabei abandonando o Jython.

Para fazer o editor de textos, você deve:

  1. Usar listeners se a funcionalidade só funcionar quando vc estiver com o cursor sobre o editor;
  2. Usar ActionMap e Keymap para ela funcionar caso ele aperte as setas em qualquer local da dele (não interessando onde esteja o foco).

Para a parte de animação, sim, é necessário usar threads. Alguns tutoriais de Java2D do Ponto V cobrem exclusivamente essa parte:
http://pontov.com.br/site/java/48-java2d/121-o-loop-de-animacao
http://pontov.com.br/site/java/48-java2d/123-a-primeira-animacao
http://pontov.com.br/site/java/48-java2d/124-desenho-direto-active-rendering

E parabéns pelo seu editor, ficou muito bacana.

Valeu cara, dei uma olhada melhor em concorrência e com o código abaixo consegui fazer a “pista” se mover. Só falta agora criar o carro , os obstáculos, e fazer com que o python reconheça os eventos de teclas(python parece que nem tem listenners :frowning: ).

						StringBuffer jogo = new StringBuffer("import time" +
								"\nimport thread" +
								"\nvezes = 0" +
								"\ndef brincar():" +
								"\n    thread.start_new_thread(deslocaPista,())" +
								"\ndef deslocaPista():"+
								"\n   global vezes"+
								"\n   while(vezes< 6000):" +
								"\n      soma = ((vezes%4)*30)" +
								"\n      alterarCorPrimaria(Color.black)" +
								"\n      desenharRetangulo(Point(0,0),Point(400,400))" +
								"\n      alterarCorPrimaria(Color.white)" +
								"\n      desenharRetangulo(Point(185,(-130)+soma),Point(215,(-40)+soma))" +
								"\n      desenharRetangulo(Point(185,0+soma),Point(215,90+soma))" +
								"\n      desenharRetangulo(Point(185,110+soma),Point(215,200+soma))" +
								"\n      desenharRetangulo(Point(185,220+soma),Point(215,310+soma))" +
								"\n      time.sleep(0.3)" +
						"\n      vezes= vezes+1" );
						engine.eval(jogo.toString());

Vou ter criar um keypressed então mesmo pro text box num é, beleza, só queria saber mesmo.

É interessante como eu olhava praqueles métodos de concorrência na api padrão e num via importância na maioria deles. Foi só eu ativar esse código ai que já começo a parecer de um monte de exceção randômica, dizendo que minha lista tava sendo alterada por uma thead que não a criou, que tinha nullpointer em algumas cores.

Outra coisa óbvia também foi o flirck gigantesco, mesmo num código tão simples.

Lendo os comentários do artigo do viny, vi com um certo pesar que java é fraco em tudo que meu programa vai se basear a longo prazo: 3D, sons e jogos. Pelo jeito vai ter que sair tudo na mão mesmo(aidna bem que não conto com isso pra me alimentar). Quem em 2020 eu tenha feito algo concreto e maduro, vamo ver né.

Bem galera, resolvido os dois problemas o código final fico assim:

/**
 * Arquivo onde é armazenado o interpretador de scripts do programa
 */
package br.ericware.programa;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Set;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/** Classe responsável por executar todo e qualquer script necessário para execução do programa
 * @author elisson
 *
 */
public class Interpretador implements ActionListener, KeyListener{

	/**
	 * Armazena o módulo 2D
	 */
	private Mod2D mod2D;

	/**
	 * Armazena o desenhista, por onde os desenhos são feitos
	 */
	private Desenhista desenhista;

	/**
	 * Armazena todo um histórico de comandos
	 */
	private LinkedList<String> comandos = new LinkedList<String>();
	
	/**
	 * Cria a conexão com o interpretador Python
	 */
	private ScriptEngine engine = new ScriptEngineManager().getEngineByName("python");

	/**
	 * Armazena a atual posição do historico
	 */
	private ListIterator<String> historico = comandos.listIterator();
	
	/**
	 * Armazena o que foi digitado na linha de comando
	 */
	private String linhaAtual;
	
	/**
	 * Construtor que recebe como parâmetro o móludo de desenho e o desenhista
	 * @param m2d o módulo2D de onde virão os scripts
	 * @param ds o desenhista do módulo em questão
	 */
	public Interpretador(Mod2D m2d, Desenhista ds) {
		this.mod2D = m2d;
		this.desenhista = ds;
		try {
			engine.eval("from " + Executor.class.getPackage().getName() + " import "+ Executor.class.getSimpleName());

			Set<Class> classes = new HashSet<Class>();

			for (Method metodo : Executor.class.getMethods()) {
				if(Modifier.isPublic( metodo.getModifiers())){
					if(metodo.getName() != "brincar"){
						classes.addAll(Arrays.asList(metodo.getParameterTypes()));
						classes.add(metodo.getReturnType());
						StringBuffer sb =  new StringBuffer("def "+ metodo.getName()+"(");
						for(int i = 0; i < metodo.getParameterTypes().length;i++){
							if(i > 0)
								sb.append(",");
							sb.append("param" + i);

						}
						sb.append("):");
						StringBuffer chamada = new StringBuffer("return "+Executor.class.getSimpleName()+"."+metodo.getName()+"(");
						for(int i = 0; i < metodo.getParameterTypes().length;i++){
							if(i > 0)
								chamada.append(",");
							chamada.append("param" + i);
						}
						chamada.append(")");
						engine.eval(sb.toString()+"\n   "+chamada.toString());
					}else{
						StringBuffer jogo = new StringBuffer("\nfrom javax.swing import SwingUtilities" +
								"\nimport sys,random,threading,thread,time,math" +
								"\ndeslocamento = 0" +
								"\ndef mover(direcao):" +
								"\n   global deslocamento" +
								"\n   if(direcao == 'Left'):" +
								"\n      if(deslocamento>-200):" +
								"\n         deslocamento -= 10" +
								"\n   elif(direcao == 'Right'):" +
								"\n      if(deslocamento<200):" +
								"\n         deslocamento += 10" +
								"\ndef brincar():" +
								"\n   thread.start_new_thread(deslocaPista,())" +
								"\nobstaculos = [[0,random.randint(0, 400)],[0,random.randint(0, 400)]]" +
								"\ndef desenhaObs():" +
								"\n   global obstaculos" +
								"\n   alterarCorPrimaria(Color.orange)" +
								"\n   for obs in obstaculos:" +
								"\n      desenharCirculo(Point(obs[1],obs[0]),30)" +
								"\ndef deslocaObs():" +
								"\n   global obstaculos" +
								"\n   for obs in obstaculos:" +
								"\n      obs[0] = obs[0] +25" +
								"\ndef reiniciaObs():" +
								"\n   global obstaculos" +
								"\n   for obs in obstaculos:" +
								"\n      if(obs[0]>400):" +
								"\n         obs[0] = 0" +
								"\n         obs[1] = random.randint(0, 400)" +
								"\ndef detectaColisao():" +
								"\n   global obstaculos" +
								"\n   global deslocamento"+
								"\n   for obs in obstaculos:" +
								"\n      if(obs[0]<330):" +
								"\n         continue" +
								"\n      distx1 = (obs[1])-(deslocamento+250)" +
								"\n      distx2 = (150+deslocamento) - (obs[1])" +
								"\n      print distx1,distx2" +
								"\n      if(distx1<30 and distx2<30):" +
								"\n         if(distx1>0 and math.sqrt(distx1**2+(360 - obs[0])**2)<30):" +
								"\n            inserirTexto(Point(130,200),'Você perdeu!HA! HA!')" +
								"\n            sys.exit(0)" +
								"\n         elif(distx2>0  and math.sqrt(distx2**2+(360 - obs[0])**2)<30):" +
								"\n            inserirTexto(Point(130,200),'Você perdeu!HA! HA!')" +
								"\n            sys.exit(0)" +
								"\n         elif(distx1<0 and distx2<0):" +
								"\n            inserirTexto(Point(130,200),'Você perdeu!HA! HA!')" +
								"\n            sys.exit(0)" +
								"\ndef deslocaPista():" +
								"\n   global deslocamento"+
								"\n   vezes = 0"+
								"\n   while(vezes< 570):" +
								"\n      soma = ((vezes%4)*25)" +
								"\n      reiniciaObs()" +
								"\n      alterarCorPrimaria(Color.black)" +
								"\n      desenharRetangulo(Point(0,0),Point(400,400))" +
								"\n      alterarCorPrimaria(Color.white)" +
								"\n      desenharRetangulo(Point(185,-95+soma),Point(215,-10+soma))" +
								"\n      desenharRetangulo(Point(185,(305)+soma),Point(215,(390)+soma))" +
								"\n      desenharRetangulo(Point(185,5+soma),Point(215,90+soma))" +
								"\n      desenharRetangulo(Point(185,105+soma),Point(215,190+soma))" +
								"\n      desenharRetangulo(Point(185,205+soma),Point(215,290+soma))" +
								"\n      alterarCorPrimaria(Color.red)" +
								"\n      desenharRetangulo(Point(150+deslocamento,360),Point(250+deslocamento,400))" +
								"\n      desenhaObs()" +
								"\n      detectaColisao()" +
								"\n      deslocaObs()" +
								"\n      time.sleep(0.3-((vezes//30)/20))" +
								"\n      " +
						"\n      vezes= vezes+1" +
						"\n   inserirTexto(Point(130,200),'Você zerou!!!!!')" );
						engine.eval(jogo.toString());
					}
				}
			}
			for(Class classe :classes){
				if(!classe.isPrimitive()){
					engine.eval("from " + classe.getPackage().getName() + " import "+ classe.getSimpleName());
				}
			}
		} catch (ScriptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub

		JTextField linhaComando =  (JTextField) e.getSource();
		try {
			engine.eval(linhaComando.getText());
		} catch (ScriptException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		if(!linhaComando.getText().equals(comandos.peekLast())){
			comandos.add(linhaComando.getText());
			historico = comandos.listIterator(comandos.size());
		}
		linhaComando.setText("");
	}

	@Override
	public void keyPressed(KeyEvent arg0) {
		// TODO Auto-generated method stub
		JTextField linhaComando =  (JTextField) arg0.getSource();
		if(arg0.getKeyCode() == KeyEvent.VK_UP){
			if(historico.hasPrevious()){
				if(!historico.hasNext())
					linhaAtual = linhaComando.getText();
				linhaComando.setText(historico.previous());
			}
		}else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){
			if(historico.hasNext())
				linhaComando.setText(historico.next());
			else
				linhaComando.setText(linhaAtual);
		}else if(!arg0.isActionKey()){
			historico = comandos.listIterator(comandos.size());
		}
		try {
			engine.eval("\nmover('"+KeyEvent.getKeyText(arg0.getKeyCode())+"')");
		} catch (ScriptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

}

O flirck lógico só aumento, ms um futuro eu eleimino esse problema, valeu pela ajuda.

Para eliminar o flickering, você deve usar Double Buffering.

No Java, há duas formas de fazer isso:

  1. Criar uma BufferedImage com o desenho da tela pronto (FrontBuffer), e outra de trabalho (BackBuffer). Você desenha no BackBuffer e, quando a pintura for concluída, substitui o FrontBuffer pelo BackBuffer e cria uma nova BufferedImage para o BackBuffer.

Se quiser evitar ficar criando e destruindo BufferedImages, você pode troca-las ao invés de descartar a de pintura.

Se você estiver chamando constantemente o método de pintura, o processo pode ser simplificado, pois pode deixar a própria janela como FrontBuffer e usar só uma imagem auxiliar no método paint. Basta então criar uma BufferedImage do tamanho da tela no início do paint, desenhar nessa BufferedImage, e ao final do paint desenhar essa imagem na tela. Um exemplo dessa técnica pode ser visto aqui: http://www.guj.com.br/java/128713-jframe-com-imagem-em-fade#1165351

  1. Usar renderização ativa, através da classe BufferStrategy. Essa técnica é explicada aqui:
    http://pontov.com.br/site/java/48-java2d/124-desenho-direto-active-rendering

Legal essa explicação, mas não vou implementar agora, porque o objetivo do script é mostrar como com a linha de comando, se pode fazer várias coisas. Quero primeiro estabelecer o módulo de desenho como algo mais sólido. Depois, vou torná-lo um módulo do programa. Ai sim eu crio o módulo de animação, de modulação 3D, de edição de som, de animação 3D, etc. Por hora fica assim mesmo.

Ah, pra quem quer testar como ficou:
https://sourceforge.net/projects/universopessoal/files/latest/download?source=files