public void run() {
		long beforeTime, afterTime, timeDiff, sleepTime;
		long overSleepTime = 0L, excess = 0L;
		int noDelays = 0;
		
		beforeTime = System.currentTimeMillis();
		
		running = true;
		
		while (running) {
			gameUpdate();	// actualizar los elementos del juego
			gameRender();	// pintar los elementos a un buffer
			paintScreen();	// pintar el buffer en la pantalla
			
			afterTime = System.currentTimeMillis();
			timeDiff = afterTime - beforeTime;
			sleepTime = (period - timeDiff) - overSleepTime;
			
			if (sleepTime > 0) {
				try {
					Thread.sleep(sleepTime);
				}
				catch (InterruptedException ex) {
					System.out.println("Error mientras dormia");
				}
				
				// comparar cuanto durmio en verdad el thread en comparacion a cuanto debia
				overSleepTime = (System.currentTimeMillis() - afterTime) - sleepTime;
			}
			else { // sleepTime <= 0 : la actualizacion/animacion tardo mucho asi que no duerme esta iteracion
				overSleepTime = 0L;
				excess -= sleepTime; // se acumula el tiempo que se excedio el bucle de juego en esta iteracion
				
				// Cuando ha habido muchos retardos, el thread cede la prioridad a otros threads
				if (++noDelays >= NO_DELAYS_PER_YIELD) {
					Thread.yield();
					noDelays = 0;
				}
			}
			
			beforeTime = System.currentTimeMillis();
			
			// Saltar frames cuando el tiempo acumulado que se excede el bucle de juego es mayor a un frame (10 ms)
			int skips = 0;
			while ((excess > period) && (skips < MAX_FRAME_SKIPS)) {
				excess -= period;
				gameUpdate(); // actualizar sin llamar al render o paint para saltar frames de la animacion
				skips++;
			}
		}
		
		System.exit(0); // cerrar el JApplet/JFrame
	}