Почему нет view.invalidate, чтобы сразу перерисовать экран в моей андроидной игре
Я пытаюсь сделать игру для Android.
У меня есть игровой класс, который расширяет активность и обрабатывает все пользовательские ввода. Затем у меня есть класс missionView, который расширяет представление и рисует уровень на экране.
Когда пользователь нажимает на дверь, я хочу добавить анимацию.
Что происходит: игра вызывает door.open. Изменяет состояние, так что функция view.onDraw будет закрывать дверь наполовину. Игра вызывает view.invalidate, которая должна перерисовывать экран. Затем игра спит полсекунды. Затем он снова вызывает дверь. Во второй раз функция называется изменением состояния, так что функция view.onDraw полностью открывает дверь. Затем игра вызывает view.invalidate снова.
Проблема заключается в том, что она не перерисовывает экран, когда он получает view.invalidate. Если я установил точку прерывания в строке и запустил отладчик и нажимаю на нее, он не будет входить в мою функцию view.onDraw. Он даже не может показать мне код, который он выполняет.
У меня есть:
Класс двери:
public boolean open()
{
if (doorState == DoorState.Closed)
{
doorState = DoorState.Opening;
return true;
}
else if (doorState == DoorState.Opening)
{
doorState = doorState.Open;
return true;
}
else
{
return false;
}
}
Класс игры:
if (tile instanceof DoorTile)
{
DoorTile doorTile = (DoorTile) tile;
Door door = doorTile.getDoor();
if (door.isClosed())
{
door.open();
selectedEntity.openDoor();
view.invalidate(); // This line does not work
try
{
Thread.sleep(500);
}
catch (InterruptedException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
door.open();
// Handled touch event so break switch statement
break;
}
}
Ответы
Ответ 1
View # invalidate сообщает системе перерисовывать (через onDraw) представление, как только основной поток переходит в режим ожидания. То есть при вызове недействительных расписаний ваше представление будет перерисовано после завершения всех других немедленных работ. Если код в вашем классе Game вызывается из основного потока, и он помещает этот поток в режим сна, вы не просто приостанавливаете рендеринг, вы все время приостанавливаете обработку ввода (обычно это плохая идея). Как правило, никогда не спите нить, которую вы не породили, если вы не знаете, что делаете.
Если вы хотите, чтобы ваша логика игры периодически задерживалась с помощью Thread # sleep, запустите ее в отдельном потоке и используйте view.postInvalidate(), чтобы сигнализировать основному потоку, чтобы он проснулся и вызывается onDraw.
Ответ 2
Для игр я фактически использовал бы более низкий уровень доступа к графике. LunarLander от Google - отличный пример для этого. В основном вам нужно сделать две вещи:
- вместо Использовать SurfaceView
- Получить обработчик из SurfaceView
-
заменить view.invalidate() на пользовательский метод repaint(), который будет содержать
private void repaint() {
Canvas c = null;
try {
c = surfaceHolder.lockCanvas();
paint(c);
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
Метод краски будет содержать то, что у вас есть в View.onDraw в настоящий момент
Ответ 3
Я столкнулся с той же проблемой в своем приложении.
В моем случае я пытался вызвать invalidate()
из метода [doInBackground()][1]
[AsyncTask][2]
.
Проблема была решена путем перемещения метода invalidate()
в [onProgressUpdate()][3]
AsyncTask
. То есть вы не можете обновить пользовательский интерфейс из метода doInBackground()
AsyncTask
. Это упоминается в документах Android, но об этом так легко забыть... поэтому не забудьте проверить его.
Ответ 4
Я могу опоздать, но я уверен, что это сработает для вас.
Я сделал это с Kotlin. Вы можете изменить в соответствии с Java.
Поместите свой код внутрь runOnUIThread()
.
Пример кода:
activity?.runOnUiThread {
// Your code goes here
}
Надеюсь, это поможет.