Оптимизация или создание игры со скоростью 60 FPS для Android, написанной на Java ⇐ Android

Форум для тех, кто программирует под Android
Anonymous
Оптимизация или создание игры со скоростью 60 FPS для Android, написанной на Java

Сообщение Anonymous »

Я хочу создать собственную игру, используя Java в студии Android. У меня есть идея: сделать онлайн-пиксельный шутер. Кстати, когда я добавлял карту, неважно какого размера, у меня были «лаги», как я тестировал с 15 FPS. Для создания этой игры я использовал SurfaceView. Игра работает со скоростью 60 кадров в секунду, метод update() обрабатывает игровую логику, а метод draw() визуализирует игру.
update()
private void update() {
// Оновлення стану прискорення
if (isAccelerated && System.currentTimeMillis() - accelerationStartTime > ACCELERATION_DURATION) {
isAccelerated = false;
playerSpeed = DEFAULT_PLAYER_SPEED;
}

// Оновлення позиції гравця
PointF direction = joystick.getDirection();
int newPlayerX = playerX + (int) (direction.x * playerSpeed);
int newPlayerY = playerY + (int) (direction.y * playerSpeed);

if (!tileMap.isWall(newPlayerX / tileMap.getTileSize(), newPlayerY / tileMap.getTileSize())) {
playerX = newPlayerX;
playerY = newPlayerY;
}

// Оновлення стрільби
if (isShooting) {
player.shoot();
}

camera.update(playerX, playerY);
}

шнурок> private void draw() {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
try {
canvas.drawColor(0xFFFFFFFF);

tileMap.draw(canvas, camera.getX(), camera.getY());

canvas.drawBitmap(
playerBitmap,
playerX - camera.getX(),
playerY - camera.getY(),
null
);

// Малювання кулі
if (isShooting) {
canvas.drawBitmap(
bulletBitmap,
bulletX - camera.getX(),
bulletY - camera.getY(),
null
);
}

joystick.draw(canvas);

// Малювання кнопок
shootButton.draw(canvas);
accelerateButton.draw(canvas);
} finally {
getHolder().unlockCanvasAndPost(canvas);
}
}
}

Игрок может перемещаться с помощью джойстика, стрелять пулями и активировать временное увеличение скорости. Класс TileMap отвечает за рендеринг карты
//TileMap.java
package com.ccs.mempixel.game;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.SparseArray;

import com.ccs.mempixel.R;

public class TileMap {
private int[][] map; // Масив, що описує карту
private Bitmap[] tileImages; // Зображення для кожного типу тайла
private int tileSize; // Розмір одного тайла (наприклад, 32x32 пікселів)
private Bitmap cachedVisibleMap; // Кешована видима частина карти
private int cachedCameraX, cachedCameraY; // Кешовані координати камери
private SparseArray collisionCache = new SparseArray();

public boolean isWall(int x, int y) {
int key = y * map[0].length + x; // Унікальний ключ для кешування
Boolean cachedResult = collisionCache.get(key);
if (cachedResult != null) {
return cachedResult;
}

boolean result;
if (y >= 0 && y < map.length && x >= 0 && x < map[y].length) {
result = map[y][x] == 1; // 1 - стіна
} else {
result = true; // Якщо координати поза межами карти, вважаємо це стіною
}

collisionCache.put(key, result);
return result;
}

public void draw(Canvas canvas, int cameraX, int cameraY) {
if (cachedVisibleMap == null || cachedCameraX != cameraX || cachedCameraY != cameraY) {
// Якщо кеш неактуальний, створюємо новий
cachedCameraX = cameraX;
cachedCameraY = cameraY;
cachedVisibleMap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas cacheCanvas = new Canvas(cachedVisibleMap);

int screenWidth = canvas.getWidth();
int screenHeight = canvas.getHeight();

int startX = Math.max(0, cameraX / tileSize);
int startY = Math.max(0, cameraY / tileSize);
int endX = Math.min(map[0].length, (cameraX + screenWidth) / tileSize + 1);
int endY = Math.min(map.length, (cameraY + screenHeight) / tileSize + 1);

for (int y = startY; y < endY; y++) {
for (int x = startX; x < endX; x++) {
int tileType = map[y][x];
if (tileType >= 0 && tileType < tileImages.length) {
cacheCanvas.drawBitmap(
tileImages[tileType],
x * tileSize - cameraX,
y * tileSize - cameraY,
null
);
}
}
}
}

// Малюємо кешовану видиму частину карти
canvas.drawBitmap(cachedVisibleMap, 0, 0, null);
}

public TileMap(Context context, int[][] map, int tileSize) {
this.map = map;
this.tileSize = tileSize;

// Завантаження зображень для тайлів
tileImages = new Bitmap[2]; // 0 - підлога, 1 - стіна
tileImages[0] = BitmapFactory.decodeResource(context.getResources(), R.drawable.floor1); // Підлога
tileImages[1] = BitmapFactory.decodeResource(context.getResources(), R.drawable.wall1); // Стіна

// Масштабування зображень до розміру тайла
for (int i = 0; i < tileImages.length; i++) {
tileImages = Bitmap.createScaledBitmap(tileImages, tileSize, tileSize, false);
}
}

// Отримання розмірів карти в пікселях
public int getMapWidth() {
return map[0].length * tileSize;
}

public int getMapHeight() {
return map.length * tileSize;
}

// Отримання розміру тайла
public int getTileSize() {
return tileSize;
}

}

и класс Camera гарантирует, что игрок останется в центре экрана.
//Camera.java
package com.ccs.mempixel.game;

public class Camera {
private int x, y; // Позиція камери
private int screenWidth, screenHeight; // Розміри екрану
private int mapWidth, mapHeight; // Розміри карти
private float smoothSpeed = 0.1f; // Швидкість плавного переміщення
private int lastPlayerX = -1;
private int lastPlayerY = -1;

public Camera(int screenWidth, int screenHeight, int mapWidth, int mapHeight) {
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
this.mapWidth = mapWidth;
this.mapHeight = mapHeight;
}

// Оновлення позиції камери (слідкування за гравцем)
public void update(int playerX, int playerY) {
if (lastPlayerX != playerX || lastPlayerY != playerY) {
lastPlayerX = playerX;
lastPlayerY = playerY;

int targetX = playerX - screenWidth / 2;
int targetY = playerY - screenHeight / 2;

// Плавне переміщення камери
x += (targetX - x) * smoothSpeed;
y += (targetY - y) * smoothSpeed;

// Обмеження руху камери
x = Math.max(0, Math.min(x, mapWidth - screenWidth));
y = Math.max(0, Math.min(y, mapHeight - screenHeight));
}
}

// Отримання позиції камери
public int getX() {
return x;
}

public int getY() {
return y;
}
}

Основной метод, запускающий весь код:
@Override
public void run() {
long lastTime = System.nanoTime();
double nsPerUpdate = 1000000000.0 / 60.0; // 60 FPS
double delta = 0;

while (isRunning) {
long now = System.nanoTime();
delta += (now - lastTime) / nsPerUpdate;
lastTime = now;

while (delta >= 1) {
update();
delta--;
}

draw();
}
}

Я пытаюсь ускорить код:
  • Добавить производительность оборудования в манифест:

= 1) {
update();
delta--;
}

draw();
}
}

private void update() {
// Оновлення стану прискорення
if (isAccelerated && System.currentTimeMillis() - accelerationStartTime > ACCELERATION_DURATION) {
isAccelerated = false;
playerSpeed = DEFAULT_PLAYER_SPEED;
}

// Оновлення позиції гравця
PointF direction = joystick.getDirection();
int newPlayerX = playerX + (int) (direction.x * playerSpeed);
int newPlayerY = playerY + (int) (direction.y * playerSpeed);

if (!tileMap.isWall(newPlayerX / tileMap.getTileSize(), newPlayerY / tileMap.getTileSize())) {
playerX = newPlayerX;
playerY = newPlayerY;
}

// Оновлення стрільби
if (isShooting) {
player.shoot();
}

camera.update(playerX, playerY);
}

private void draw() {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
try {
canvas.drawColor(0xFFFFFFFF);

tileMap.draw(canvas, camera.getX(), camera.getY());

canvas.drawBitmap(
playerBitmap,
playerX - camera.getX(),
playerY - camera.getY(),
null
);

// Малювання кулі
if (isShooting) {
canvas.drawBitmap(
bulletBitmap,
bulletX - camera.getX(),
bulletY - camera.getY(),
null
);
}

joystick.draw(canvas);

// Малювання кнопок
shootButton.draw(canvas);
accelerateButton.draw(canvas);
} finally {
getHolder().unlockCanvasAndPost(canvas);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
if (accelerateButton.isTouched(touchX, touchY)) {
playerSpeed = ACCELERATED_PLAYER_SPEED;
isSpeedButtonPressed = true;
isShootButtonPressed = false;
return true;
}

if (shootButton.isTouched(touchX, touchY)) {
isShootButtonPressed = true;
isSpeedButtonPressed = false;
return true;
}

isSpeedButtonPressed = false;
isShootButtonPressed = false;
joystick.updateHandle(touchX, touchY);
break;

case MotionEvent.ACTION_UP:
isSpeedButtonPressed = false;
isShootButtonPressed = false;
joystick.resetHandle();
break;
}
return true;
}

private Point getRandomFloorPosition(int[][] map) {
Random random = new Random();
int x, y;

// Шукаємо випадкову позицію, де є підлога (0)
do {
x = random.nextInt(map[0].length);
y = random.nextInt(map.length);
} while (map[y][x] != 0);

return new Point(x, y);
}
}


Подробнее здесь: https://stackoverflow.com/questions/793 ... using-java

Вернуться в «Android»