Density – Sachen in gleichem Verhältnis zeichnen
In unserem Zusammenhang ist die Density die Dichte der Pixel unseres Bildschirms. Gehen wir z.B. von einem Bildschirm A mit 4 Zoll und 1280*720 Pixeln aus und eineml Bildschirm B mit 3 Zoll und mit der gleichen Anzahl an Pixeln, dann ist die Density des Bildschirms B höher. Da pro Fläche mehr Pixel vorhanden sind. Dazu gibt es eine Einheit dpi (dots per inch).
Und das brauchen wir jetzt, damit wir unser Spiel Bildschirmgrößenunabhängig (ganz schön langes Wort) machen können.
Zuerst müssen wir die Variable density global anlegen.
private float density;
Die Density des Bildschirms
public float getDensity() {
density = getResources().getDisplayMetrics().density;
return density;
}
Nun müssen wir alle Werte die bisher reine Zahlen waren und auf unseren Canvas gemalt wurden mit getDensity multiplizieren. Und da es sich um Integer Werte handelt, die wir mit density multiplizieren, dürfen wir nicht vergessen zu casten.
Kopiert dazu am besten den folgenden Code und ersetzt ihn mit euren Klassen GameView und Sprite.
package com.panjutorials.lazypudding;
import java.util.Random;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
public class Sprite {
static final private int BMP_COLUMNS = 4;
static final private int BMP_ROWS = 4;
private int[] DIRECTION_TO_SPRITE_SHEET = { 2, 0, 3, 1 };
private int x;
private int y;
private int xSpeed;
private int ySpeed;
private int width;
private int height;
private Bitmap bmp;
private GameView theGameView;
private int currentFrame=0;
public Sprite(GameView theGameView, Bitmap bmp) {
this.theGameView = theGameView;
this.bmp = bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
Random rnd = new Random();
x = (int) (30 * theGameView.getDensity() + rnd.nextInt((int) (theGameView
.getWidth() - width - 50 * theGameView.getDensity())));
y = (int) (30 * theGameView.getDensity() + rnd.nextInt((int) (theGameView
.getHeight() - height - 50 * theGameView.getDensity())));
ySpeed = (int) ((rnd.nextInt(10) - 4)*theGameView.getDensity());
xSpeed = (int) ((rnd.nextInt(10) - 4)*theGameView.getDensity());
}
private void bounceOff() {
if (x + 10*theGameView.getDensity() > theGameView.getWidth() - width - xSpeed || x + xSpeed < 10*theGameView.getDensity()) {
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y + 10*theGameView.getDensity()> theGameView.getHeight() - height - ySpeed || y + ySpeed < 0) {
ySpeed = -ySpeed;
}
y = y + ySpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
}
public void onDraw(Canvas canvas) {
bounceOff();
int sourceX = currentFrame * width;
int sourceY = getAnimationRow() * height;
Rect source = new Rect(sourceX, sourceY, sourceX + width, sourceY + height);
Rect destine = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, source, destine, null);
}
private int getAnimationRow() {
double directionDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2)+2);
int spriteDir = (int) Math.round(directionDouble) % BMP_ROWS;
return DIRECTION_TO_SPRITE_SHEET[spriteDir];
}
public boolean isTouched(float x2, float y2) {
return x2 > x && x2 < x + width && y2 > y && y2 < y + height;
}
}
Hierbei habe ich die Werte an denen die Sprites starten etwas verändert, damit sie noch weiter vom Rand entfernt generiert werden.
Und die GameView
package com.panjutorials.lazypudding;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView {
private List<Sprite> spriteList = new ArrayList<Sprite>();
private List<Integer> spriteListNum = new ArrayList<Integer>();
private SurfaceHolder surfaceHolder;
private Bitmap bmp;
private GameLoopThread theGameLoopThread;
private boolean createSprites = true;
private long lastClick;
private int currentColorNum;
private Paint paintRed, paintBlue, paintGreen, paintYellow;
private Paint currentColor;
private String scoreString;
private int score = 0;
private float density;
public GameView(Context context) {
super(context);
Random rnd = new Random();
setColors();
currentColorNum = rnd.nextInt(4);
theGameLoopThread = new GameLoopThread(this);
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
theGameLoopThread.setRunning(false);
while (retry) {
try {
theGameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
theGameLoopThread.setRunning(true);
theGameLoopThread.start();
}
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// TODO Auto-generated method stub
}
});
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.DKGRAY);
if (createSprites == true) {
initialSprites();
}
for (Sprite sprite : spriteList) {
sprite.onDraw(canvas);
}
if (currentColorNum == 0) {
drawLines(paintBlue, canvas);
} else if (currentColorNum == 1) {
drawLines(paintRed, canvas);
} else if (currentColorNum == 2) {
drawLines(paintGreen, canvas);
} else if (currentColorNum == 3) {
drawLines(paintYellow, canvas);
}
final int fontSize = (int) (25 * density);
int yTextPos = (int) (25 * density);
Typeface font = Typeface.create("Arial", Typeface.NORMAL);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTypeface(font);
paint.setTextSize(fontSize);
paint.setAntiAlias(true);
scoreString = String.valueOf(score);
int x = (canvas.getWidth() * 5 / 7);
final String text = "Score: " + scoreString;
canvas.drawText(text, x, yTextPos, paint);
}
private void createSprite(int index) {
Bitmap bmp = null;
switch (index) {
case 0:
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.alienspriteblue);
break;
case 1:
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.alienspritered);
break;
case 2:
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.alienspritegreen);
break;
case 3:
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.alienspriteyellow);
break;
}
Sprite sprite = new Sprite(this, bmp);
spriteList.add(sprite);
spriteListNum.add(index);
}
private void initialSprites() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3; j++)
createSprite(i);
}
createSprites = false;
}
private void rndCreateSprite() {
Random rnd = new Random(System.currentTimeMillis());
int i = rnd.nextInt(4);
createSprite(i);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 300) {
lastClick = System.currentTimeMillis();
synchronized (getHolder()) {
for (int i = spriteList.size() - 1; i >= 0; i--) {
Sprite sprite = spriteList.get(i);
if (sprite.isTouched(event.getX(), event.getY())) {
if (currentColorNum == spriteListNum.get(i)) {
score++;
}
rndCreateSprite();
removeSprite(i);
changeColor();
break;
}
}
}
}
return true;
}
private void removeSprite(int index) {
spriteList.remove(index);
spriteListNum.remove(index);
}
public void setColors() {
Paint paintRed = new Paint();
paintRed.setARGB(255, 236, 27, 36);
this.paintRed = paintRed;
Paint paintBlue = new Paint();
paintBlue.setARGB(255, 36, 72, 204);
this.paintBlue = paintBlue;
Paint paintGreen = new Paint();
paintGreen.setARGB(255, 34, 177, 76);
this.paintGreen = paintGreen;
Paint paintYellow = new Paint();
paintYellow.setARGB(255, 255, 242, 0);
this.paintYellow = paintYellow;
}
public void drawLines(Paint lineColor, Canvas canvas) {
int lineWidth = 10;
int screenHeight = getHeight();
int screenWidth = getWidth();
canvas.drawRect(0, 0, lineWidth, getHeight(), lineColor);
canvas.drawRect(0, getHeight() - lineWidth, screenWidth, screenHeight,
lineColor);
canvas.drawRect(screenWidth - lineWidth, 0, screenWidth, screenHeight,
lineColor);
currentColor = lineColor;
}
public void changeColor() {
Random rnd = new Random();
int index = rnd.nextInt(spriteListNum.size());
this.currentColorNum = spriteListNum.get(index);
switch (index) {
case 0:
currentColor = paintBlue;
break;
case 1:
currentColor = paintRed;
break;
case 2:
currentColor = paintGreen;
break;
case 3:
currentColor = paintYellow;
break;
}
}
public float getDensity() {
density = getResources().getDisplayMetrics().density;
return density;
}
}