Optimierung oder Erstellung von 60 FPS für Android-Spiele, die mit Java geschrieben wurdenAndroid

Forum für diejenigen, die für Android programmieren
Guest
 Optimierung oder Erstellung von 60 FPS für Android-Spiele, die mit Java geschrieben wurden

Post by Guest »

Ich möchte ein eigenes Spiel mit Java in Android Studio erstellen. Ich habe eine Idee: Online-Pixel-Shooter machen. Übrigens, als ich die Karte hinzugefügt habe, egal welche Größe ich habe, habe ich „Verzögerungen“, da ich mit 15 FPS teste. Ich habe SurfaceView verwendet, um dieses Spiel zu erstellen. Das Spiel läuft mit 60 FPS, wobei die update()-Methode die Spiellogik verwaltet und die draw()-Methode das Spiel rendert.
update()

Code: Select all

    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);
}
drawstring>

Code: Select all

 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);
}
}
}
Der Spieler kann sich mit einem Joystick bewegen, Kugeln abfeuern und einen vorübergehenden Geschwindigkeitsschub aktivieren. Die TileMap-Klasse übernimmt das Kartenrendering

Code: Select all

//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[i] = Bitmap.createScaledBitmap(tileImages[i], tileSize, tileSize, false);
}
}

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

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

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

}
und die Kameraklasse sorgen dafür, dass der Player auf dem Bildschirm zentriert bleibt.

Code: Select all

//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;
}
}
Es gibt eine Hauptmethode, die den gesamten Code startet:

Code: Select all

@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();
}
}
Mein Versuch, den Code zu beschleunigen:
  • Hardwareleistung im Manifest hinzufügen:

Code: Select all

= 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);
}
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post