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

Форум для тех, кто программирует под 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
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

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