I am creating a mini game for Android, available from the playstore, which we call "Moon Buggy". The action is that you control a vehicle on the moon and you should defend yourself from attacking UFO:s.
Now I want to improve the movement of the vehicle. I have code so that it doesn't move outside the screen, and it is possible to accelerate, slow down and jump. But it is not perfect. I was inspired by the classic game Moon Patrol which is measuring time per completed section and my game does that too. So preferably you should be able to accelerate and complete the section faster the more you accelerate perhaps instead of stopping at the end of the screen which my vehicle does now. Also, perhaps it should accelerate faster.
The relevant code is:
ParallaxActivity.java
public class ParallaxActivity extends Activity implements View.OnClickListener {
long startTime;
long countUp;
TextView textGoesHere;
ParallaxView parallaxView;
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button3:
ParallaxView parallaxView = findViewById(R.id.backgroundImage);
parallaxView.recent = false;
parallaxView.brake = false;
parallaxView.buggyXDistance = parallaxView.buggyXDistance + 3;
parallaxView.distanceDelta = parallaxView.distanceDelta + 0.2;
break;
case R.id.button4:
ParallaxView parallaxView2 = findViewById(R.id.backgroundImage);
parallaxView2.recent = false;
parallaxView2.buggyXDistance = parallaxView2.buggyXDistance - 7;
parallaxView2.retardation = parallaxView2.retardation + 0.2;
parallaxView2.brake = true;
break;
case R.id.button2:
ParallaxView parallaxView3 = findViewById(R.id.backgroundImage);
parallaxView3.numberOfshots++;
parallaxView3.recent = false;
parallaxView3.launchMissile();
parallaxView3.scoring = true;
break;
case R.id.button1:
ParallaxView parallaxView4 = findViewById(R.id.backgroundImage);
if(parallaxView4.distanceDelta<3) parallaxView4.distanceDelta = parallaxView4.distanceDelta + 0.2;
parallaxView4.jump = true;
parallaxView4.shoot = false;
parallaxView4.lastTurn3 = System.currentTimeMillis();
break;
default:
break;
}
}
}
ParallaxView.java
public class ParallaxView extends SurfaceView implements Runnable, SurfaceHolder.Callback {
static int bombed = 5;
boolean waitForTimer = false;
boolean waitForTimer2 = false;
boolean waitForTimer3 = false;
boolean recent = false;
Rect fromRect1;
Rect toRect1;
Rect fromRect2;
Rect toRect2;
boolean increment = false;
int numberOfshots = 0; // change to 0
int[] missiles = new int[200];
int alienBombYDelta = 0;
int alienBombYDelta2 = 0;
int alienBombXDelta = 20;
int alienBombXDelta2 = 30;
int p = 7;
int p2 = 13;
boolean once, once2 = true;
final int buggyXDisplacement = 450;
int jumpHeight = 0;
int xbuggy2 = 0;
boolean toggleDeltaY = true;
long lastTurn2 = System.currentTimeMillis();
long lastTurn3 = System.currentTimeMillis();
boolean toggleGround = true;
boolean jump = false;
boolean shoot = false;
int index = 0;
int missileOffSetY = 0;
static int score = 0;
double buggyXDistance = 0;
double distanceDelta = 1.15;
double retardation = 0.5;
boolean checkpointComplete = false;
boolean runOnce = true;
boolean passed = false;
List<Background> backgrounds;
int spacerocki, resID, explodeID, explodeID2, alienResID2;
boolean toggle = true;
private volatile boolean running;
private Thread gameThread = null;
Bitmap explode, buggy, alien, alien2, explode2, spacerock, spacerock2, hole;
boolean alienexplode = false;
TextView tvId;
TextView checkpointtextview;
TextView checkpointtextview2;
TextView checkpointtextview3;
TextView checkpointtextview4;
TextView checkpointtextview5;
TextView checkpointtextview6;
// For drawing
private Paint paint;
private Canvas canvas;
private SurfaceHolder ourHolder;
AttackingAlien alien3;
AttackingAlien alien4, alien5;
// Holds a reference to the Activity
Context context;
// Control the fps
long fps = 60;
// Screen resolution
int screenWidth;
int screenHeight;
boolean bexplode = false;
boolean brake = false;
boolean scoring = false;
// use Handler instead
// this runs for 4 seconds and not just once after a while
class BuggyExploded extends TimerTask {
public void run() {
distanceDelta = 1.15;
retardation = 0.5;
jumpHeight = 0;
bexplode=true;
}
}
// use Handler instead
class SetRecent extends TimerTask {
public void run() {
recent = false;
}
}
// use Handler instead
class ResetCheckpoint extends TimerTask {
public void run() {
Log.d("## sectionComplete", "sectionComplete " + sectionComplete);
if (sectionComplete == 0) Background.checkpoint = 'A';
if (sectionComplete == 1) Background.checkpoint = 'F';
if (sectionComplete == 2) Background.checkpoint = 'K';
if (sectionComplete == 3) Background.checkpoint = 'P';
if (sectionComplete == 4) Background.checkpoint = 'U';
//if (sectionComplete==5) Background.checkpoint = 'U';
}
}
private void update() {
// Update all the background positions
for (Background bg : backgrounds) {
bg.update(fps);
}
}
#Override
public void run() {
while (running) {
long startFrameTime = System.currentTimeMillis();
update();
if (alienBombXDelta > screenWidth - 250 || alienBombXDelta < 10) { // UFO change direction
p = -p;
}
if (alienBombXDelta2 > screenWidth - 250 || alienBombXDelta2 < 10) { // UFO2 change direction
p2 = -p2;
}
draw();
// Calculate the fps this frame
long timeThisFrame = System.currentTimeMillis() - startFrameTime;
if (timeThisFrame >= 1) {
fps = 1000 / timeThisFrame;
}
}
}
private void checkJump() {
if (System.currentTimeMillis() - lastTurn3 >= 650) { // 650 means how long the vehicle is in the air at a jump
// Change direction here
jump = false;
lastTurn3 = System.currentTimeMillis();
}
}
private void checkBuggyBombed() {
if (recent) {
// use handlers instead
new Timer().schedule(new BuggyExploded(), 4000);
new Timer().schedule(new SetRecent(), 10000);
new Timer().schedule(new ResetCheckpoint(), 1000);
}
}
private void makeShots(Bitmap b) {
for (int i1 = 0; i1 < numberOfshots; i1++) {
if (shoot) {
canvas.drawText("o", (float) (missiles[i1] + buggyXDistance + 450), (float) (screenHeight * 0.7) - jumpHeight, paint); // add to y the jump height
canvas.drawText("o", (float) (buggyXDistance + 185 + 400), screenHeight / 110 * 95 - missiles[i1] - xbuggy2, paint);
}
if (i1 == numberOfshots - 1 && missiles[i1] > screenWidth) {
if (numberOfshots > 0) numberOfshots--;
if (index > 0) index--;
}
}
}
private void updateDeltas() {
alienBombXDelta = alienBombXDelta + p;
//make sure alien does not move too low
if (alienBombYDelta + 1 > screenHeight / 2)
alienBombYDelta=alienBombYDelta-2;
if (!toggleDeltaY)
alienBombYDelta++;
else
alienBombYDelta--;
alienBombXDelta2 = alienBombXDelta2 + p2;
if (!toggleDeltaY)
alienBombYDelta2++;
else
alienBombYDelta2--;
}
//use a Handler instead
private void changeDirections() {
if (System.currentTimeMillis() - lastTurn2 >= 7000) {
// Change direction here
toggleDeltaY = !toggleDeltaY;
lastTurn2 = System.currentTimeMillis();
}
}
//try to improve this
private void controlVelocity() {
if (!brake && buggyXDistance > 0) buggyXDistance = buggyXDistance + distanceDelta;
else if (brake && buggyXDistance > 0) buggyXDistance = buggyXDistance - retardation;
}
TextView tvId1;
int sectionComplete = 0;
private void drawDetails() {
//draw a background color
}
private void makeShots() {
for (int n = 0; n < numberOfshots; n++)
missiles[n] = missiles[n] + 20;
}
public void changeText() {
if (scoring) {
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
String str = "Player 1 " + String.format("%06d", score);
tvId.setText(str);
scoring = false;
}
});
}
}
double lastTurn4 = System.currentTimeMillis();
//change to handler
private void checkFire() {
if (System.currentTimeMillis() - lastTurn4 >= 118500) { // 18500 means how often the alien fires
lastTurn4 = System.currentTimeMillis();
missileOffSetY = 0;
}
}
private void draw() {
if (retardation > 0.5)
distanceDelta = 0;
if (distanceDelta > 0)
retardation = 0.5;
if (ourHolder.getSurface().isValid()) {
//First we lock the area of memory we will be drawing to
canvas = ourHolder.lockCanvas();
if (checkpointComplete) {
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
//
}
});
canvas.drawColor(Color.BLACK);
((ParallaxActivity) getContext()).stopWatch.stop();
paint.setTextSize(60);
String s2 = "TIME TO REACH POINT \"" + Background.checkpoint + "\"\n";
if (runOnce) {
for (int q = 0; q < s2.length(); q++) {
final String s2f = s2;
final int r = q;
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
checkpointtextview.setTextColor(Color.RED);
checkpointtextview.append(Character.toString(s2f.charAt(r)));
}
});
try {
Thread.sleep(50);
} catch (InterruptedException ie) {
}
}
}
String str = String.format("%03d", ((ParallaxActivity) this.getContext()).countUp);
String s3 = "YOUR TIME : " + str;
if (runOnce) {
for (int q = 0; q < s3.length(); q++) {
final String s3f = s3;
final int r = q;
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
checkpointtextview2.setTextColor(Color.parseColor("#ADD8E6"));
checkpointtextview2.append(Character.toString(s3f.charAt(r)));
}
});
try {
Thread.sleep(50);
} catch (InterruptedException ie) {
}
}
}
String s4 = "THE AVERAGE TIME : 060";
if (runOnce) {
for (int q = 0; q < s4.length(); q++) {
final String s4f = s4;
final int r = q;
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
checkpointtextview3.setTextColor(Color.parseColor("#ADD8E6"));
checkpointtextview3.append(Character.toString(s4f.charAt(r)));
}
});
try {
Thread.sleep(50);
} catch (InterruptedException ie) {
}
}
}
String s5 = "TOP RECORD : 060";
if (runOnce) {
for (int q = 0; q < s5.length(); q++) {
final String s5f = s5;
final int r = q;
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
checkpointtextview4.setTextColor(Color.RED);
checkpointtextview4.append(Character.toString(s5f.charAt(r)));
}
});
try {
Thread.sleep(50);
} catch (InterruptedException ie) {
}
}
}
String s6 = "GOOD BONUS POINTS : 1000";
if (runOnce) {
for (int q = 0; q < s6.length(); q++) {
final String s6f = s6;
final int r = q;
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
checkpointtextview5.setTextColor(Color.RED);
checkpointtextview5.append(Character.toString(s6f.charAt(r)));
}
});
try {
Thread.sleep(50);
} catch (InterruptedException ie) {
}
}
}
if (runOnce) {
score = score + 1000;
sectionComplete++;
recent = true;
}
runOnce = false;
// canvas.drawText("CHECKPOINT COMPLETE", (float) (screenWidth * 0.35), (float) (screenHeight * 0.45), paint);
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
((ParallaxActivity) getContext()).startTime = SystemClock.elapsedRealtime();
((ParallaxActivity) getContext()).stopWatch.setBase(((ParallaxActivity) getContext()).startTime);
((ParallaxActivity) getContext()).stopWatch.start();
checkpointtextview.setText("");
checkpointtextview2.setText("");
checkpointtextview3.setText("");
checkpointtextview4.setText("");
checkpointtextview5.setText("");
checkpointtextview6.setText("");
String str = "Player 1 " + String.format("%06d", score);
tvId.setText(str);
scoring = false;
buggyXDistance = 0;
distanceDelta = 0;
retardation = 0;
checkpointComplete = false;
runOnce = true;
}
}, 3000);
}
});
} else {
if (bombed == 0) //GAME OVER
{
final int duration = Toast.LENGTH_SHORT;
((Activity) this.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
final Toast toast = Toast.makeText(context, "GAME OVER!\nScore: " + score, duration);
toast.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toast.cancel();
bombed = 5;
score = 0;
Background.checkpoint = 'A';
String str = "Player 1 " + String.format("%06d", score);
tvId.setText(str);
}
}, 3000);
}
});
}
// adjust vehicle physics when jumping
if (jump && jumpHeight < 300) {
jumpHeight = jumpHeight + 7;
if (distanceDelta < 3) distanceDelta = distanceDelta + 0.55;
} else if (jumpHeight > 0) {
jumpHeight = jumpHeight - 4;
if (distanceDelta < 3) distanceDelta = distanceDelta + 0.55;
}
if (shoot) {
xbuggy2 = xbuggy2 + 4;
}
checkFire();
checkJump();
// drawDetails();
canvas.drawColor(Color.argb(255, 0, 0, 0));
// Draw the background parallax
drawBackground(0);
// Draw the rest of the game
paint.setTextSize(60);
paint.setColor(Color.argb(255, 255, 255, 255));
checkBuggyBombed();
makeShots(alien);
changeDirections();
alien3.update(canvas, paint, toggleDeltaY, screenWidth, screenHeight);
recent=alien3.drawMissile(this, canvas, paint, buggyXDisplacement, buggyXDistance, buggy, jumpHeight, screenHeight);
if(recent) {
waitForTimer = true;
bexplode=true;
AttackingAlien.recent = true;
}
alien4.update(canvas, paint, toggleDeltaY, screenWidth, screenHeight);
boolean recent2=alien4.drawMissile(this, canvas, paint, buggyXDisplacement, buggyXDistance, buggy, jumpHeight, screenHeight);
if(recent || recent2) {
recent = true;
waitForTimer = true;
bexplode=true;
AttackingAlien.recent = true;
}
alien5.update(canvas, paint, toggleDeltaY, screenWidth, screenHeight);
boolean recent3=alien5.drawMissile(this, canvas, paint, buggyXDisplacement, buggyXDistance, buggy, jumpHeight, screenHeight);
if(recent || recent2 || recent3) {
recent = true;
waitForTimer = true;
bexplode=true;
AttackingAlien.recent = true;
Handler handler = new Handler(Looper.getMainLooper());
// this code runs after a while
handler.postDelayed(new Runnable() {
#Override
public void run() {
recent = false;
AttackingAlien.recent = false;
waitForTimer = false;
bexplode=false;
buggyXDistance = 0;
Log.d("postDelayed", "postDelayed ");
}
}, 5000);
}
checkBuggyBombed();
for (int i1 = 0; i1 < numberOfshots; i1++) {
alien3.checkBeingHit(missiles, buggyXDisplacement, buggyXDistance, canvas, explode2, paint, score, this, i1, xbuggy2);
alien4.checkBeingHit(missiles, buggyXDisplacement, buggyXDistance, canvas, explode2, paint, score, this, i1, xbuggy2);
alien5.checkBeingHit(missiles, buggyXDisplacement, buggyXDistance, canvas, explode2, paint, score, this, i1, xbuggy2);
}
drawBackground(1);
// canvas.drawText("X", (float) (50 + buggyXDistance)+buggy.getWidth()/2, (float) (screenHeight * 0.3) - jumpHeight+buggy.getHeight(), paint);
paint.setTextSize(60);
canvas.drawText("A E J O T Z", (float) (screenWidth * 0.7), (float) (screenHeight * 0.15), paint);
// Prevent buggy from moving outside horizontal screen
if (!brake && buggyXDisplacement + buggyXDistance > screenWidth - buggy.getWidth() - 200)
buggyXDistance = screenWidth - buggy.getWidth() - 200;
//Log.d("buggyXDistance", "buggyXDistance " + buggyXDistance);
if (!bexplode && !waitForTimer && !checkpointComplete)
canvas.drawBitmap(buggy, (float) (buggyXDisplacement + buggyXDistance), (float) (screenHeight * 0.5) - jumpHeight, paint);
else if (bexplode && !checkpointComplete) {
canvas.drawBitmap(explode, (float) (buggyXDisplacement + buggyXDistance), (float) (screenHeight * 0.5) - jumpHeight, paint);
distanceDelta = 0;
retardation = 0;
}
int inc = 0;
for (int i = 0; i < bombed; i++) {
canvas.drawBitmap(Bitmap.createScaledBitmap(buggy, (int) (0.50 * (buggy.getWidth() / 3)), (int) (0.50 * buggy.getHeight() / 3), false), inc, 100, paint);
inc = inc + buggy.getWidth() / 4;
}
makeShots();
updateDeltas();
controlVelocity();
}
ourHolder.unlockCanvasAndPost(canvas);
}
}
// Clean up our thread if the game is stopped
public void pause() {
running = false;
try {
gameThread.join();
} catch (InterruptedException e) {
// Error
//e.printStackTrace();
}
}
// Make a new thread and startMissile it
// Execution moves to our run method
public void resume() {
running = true;
gameThread = new Thread(this);
gameThread.start();
}
int craterX = -550;
}
The complete code is available on request because of SO limitation of 30000 chars.
I unfortunately cannot supply you with the code for this right now (since I am at work currently), but one thing you can do is to have your fall speed (acceleration) modified depending on whether the jump button is held.
ie.
// Put this into your constant gravity function
// Or whatever you have that makes the player fall
// This should be altering a local gravity modifier in the player
if(jumpKeyHeld) {
locaGravAccel = 0.5
} else {
locaGravAccel = 1.0
}
What this does is make your jump feel more responsive as you move upwards at a nice speed, and then fall straight down to the ground quickly. It also gives the famous tap-for-low-jump-hold-for-high-jump feeling that you find in Mario games and the like.
Unless I vastly misunderstood your question, I believe this will help with game feel for you. I've implemented similar features in other projects, and people have always responded positively to this change, often claiming it feels more like a genuine 'game'.
UPDATE: Since I've noticed you don't actually have a gravity function, here is one way to do it. It is in C# for unity2D, but this is how I learned to do it, so I know it is good.
Related
I am following this tutorial on how to create a Java2D platform game. I followed the code precisely, but when I tried to run it, the player moves way too fast when moving left and when jumping and falling compared to when it's moving right.
My player class looks like this:
package Entity;
import TileMap.*;
import java.awt.*;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class Player extends MapObject {
// Player stats
private int health, maxHealth, fire, maxFire, fireCost, fireBallDamage, scratchDamage, scratchRange;
private boolean dead, flinching, firing, scratching, gliding;
private long flinchTimer;
// private ArrayList<FireBall> fireballs;
private ArrayList<BufferedImage[]> sprites;
private final int[] numFrames = { 2, 8, 1, 2, 4, 2, 5 };
// Animation actions
private static final int IDLE = 0;
private static final int WALKING = 1;
private static final int JUMPING = 2;
private static final int FALLING = 3;
private static final int GLIDING = 4;
private static final int FIREBALL = 5;
private static final int SCRATCHING = 6;
private int currentAction;
// Constructor
public Player(TileMap tm) {
super(tm);
width = height = 30;
cWidth = cHeight = 20;
moveSpeed = 0.3;
maxSpeed = 1.6;
stopSpeed = 0.4;
fallSpeed = 0.15;
maxFallSpeed = 4.0;
jumpStart = -4.8;
stopJumpSpeed = 0.3;
facingRight = true;
health = maxHealth = 5;
fire = maxFire = 2500;
fireCost = 200;
fireBallDamage = 5;
//fireBalls = new ArrayList<FireBall>();
scratchDamage = 8;
scratchRange = 40;
// Load sprites
try {
BufferedImage spritesheet =
ImageIO.read( getClass().getResourceAsStream("/Sprites/Player/playersprites.gif"));
sprites = new ArrayList<BufferedImage[]>();
// Loop through animation actions
for (int i = 0; i < 7; i++){
BufferedImage[] bi = new BufferedImage[numFrames[i]];
for (int j = 0; j < numFrames[i]; j++) {
// numFrames[6] = SCRATCH has width = 60
if (i != 6) {
bi[j] = spritesheet.getSubimage(j * width, i * height, width, height);
} else {
bi[j] = spritesheet.getSubimage(j * width * 2, i * height, width, height);
}
}
sprites.add(bi); // Add BufferedImageArray to animations list
}
} catch (Exception e) { e.printStackTrace(); }
animation = new Animation();
currentAction = IDLE;
animation.setFrames(sprites.get(IDLE));
animation.setDelay(400);
}
// Getters
public int getHealth() { return health; }
public int getMaxHealth() { return maxHealth; }
public int getFire() { return fire; }
public int getMaxFire() { return maxFire; }
// Setters
public void setFiring() { firing = true; }
public void setScratching() { scratching = true; }
public void setGliding(boolean b) { gliding = b; }
private void getNextPosition() {
// Movement
if (left) {
dx -= moveSpeed;
if ( dx < -maxSpeed) { dx = 0; }
} else if (right) {
dx += moveSpeed;
if (dx > maxSpeed) { dx = maxSpeed; }
} else {
if (dx > 0) {
dx -= stopSpeed;
if ( dx < 0 ) { dx = 0; }
} else if (dx < 0) {
dx += stopSpeed;
if (dx > 0) { dx = 0; }
}
}
// Cannot attack while moving, unless in the air
if ( currentAction == SCRATCHING || currentAction == FIREBALL && !( jumping || falling)) { dx = 0; }
// Jumping
if (jumping && !falling) {
dy += jumpStart;
falling = true;
}
if (falling) {
if ( dy > 0 && gliding) { dy += fallSpeed * 0.1; }
else { dy += fallSpeed; }
if ( dy > 0 ) { jumping = false; }
if ( dy < 0 && !jumping ) { dy += maxFallSpeed; }
if ( dy > maxFallSpeed ) { dy = maxFallSpeed; }
}
}
public void update() {
// Update position
getNextPosition();
checkTileMapCollision();
setPosition(xtemp, ytemp);
// Set animations
if (scratching) {
if (currentAction != SCRATCHING) {
currentAction = SCRATCHING;
animation.setFrames(sprites.get(SCRATCHING));
animation.setDelay(50);
width = 60;
}
} else if (firing) {
if (currentAction != FIREBALL) {
currentAction = FIREBALL;
animation.setFrames(sprites.get(FIREBALL));
animation.setDelay(100);
width = 30;
}
} else if (dy > 0) {
if (gliding) {
if (currentAction != GLIDING) {
currentAction = GLIDING;
animation.setFrames(sprites.get(GLIDING));
animation.setDelay(100);
width = 30;
}
} else if (currentAction != FALLING) {
currentAction = FALLING;
animation.setFrames(sprites.get(FALLING));
animation.setDelay(100);
width = 30;
}
} else if (dy < 0) {
if ( currentAction != JUMPING) {
currentAction = JUMPING;
animation.setFrames(sprites.get(JUMPING));
animation.setDelay(-1);
width = 30;
}
} else if ( left || right ) {
if ( currentAction != WALKING) {
currentAction = WALKING;
animation.setFrames(sprites.get(WALKING));
animation.setDelay(40);
width = 30;
}
} else {
if ( currentAction != IDLE) {
currentAction = IDLE;
animation.setFrames(sprites.get(IDLE));
animation.setDelay(400);
width = 30;
}
}
animation.update();
// Set direction
if ( currentAction != SCRATCHING && currentAction != FIREBALL) {
if ( right) { facingRight = true; }
if ( left ) { facingRight = false; }
}
}
public void draw(Graphics2D g) {
setMapPosition();
// Draw player
if (flinching) {
long elapsed = (System.nanoTime() - flinchTimer) / 1000000;
if (elapsed / 100 % 2 == 0) { return; } // Gives the appearance of blinking
}
if (facingRight) {
g.drawImage(animation.getImage(), (int) (x + xmap - width/2), (int) (y + ymap - height/2), null);
} else {
g.drawImage(animation.getImage(), (int) (x + xmap - width/2 + width), (int) (y + ymap - height/2),
-width, height, null);
}
}
}
I tried changing
private void getNextPosition() {
// Movement
if (left) {
dx -= moveSpeed;
if ( dx < -maxSpeed) { dx = -maxSpeed; }
to
private void getNextPosition() {
// Movement
if (left) {
dx -= moveSpeed;
if ( dx < -maxSpeed) { dx = 0; }
Which helped for the left-movement, but it created a lag in the graphics, so I tried changing theAnimation-class which looks like this:
package Entity;
import java.awt.image.BufferedImage;
public class Animation {
private BufferedImage[] frames;
private int currentFrame;
private long startTime, delay;
private boolean playedOnce;
public void Animation() {
playedOnce = false;
}
public void setFrames(BufferedImage[] frames) {
this.frames = frames;
currentFrame = 0;
startTime = System.nanoTime();
playedOnce = false;
}
public void setDelay(long d) { delay = d; }
public void setFrame(int i) { currentFrame = i; }
public void update() {
if (delay == -1) { return; }
long elapsed = (System.nanoTime() - startTime) / 1000000;
if (elapsed > delay) {
currentFrame++;
startTime = System.nanoTime();
}
if (currentFrame == frames.length) {
currentFrame = 0;
playedOnce = true;
}
}
public int getFrame() { return currentFrame; }
public BufferedImage getImage() { return frames[currentFrame]; }
public boolean hasPlayedOnce() { return playedOnce; }
}
Which I thought was where I could fix the problem, but I am uncertain as I am new to gamelogic. Is there any way I can slow down the movement of the player? All help is appreciated!
I'm trying to do something with the rear Camera but when i try my code the camera preview is displayed mirrored(left-to-right)...
Maybe i've written something wrong! I'm using the FSDK that is a private library.
Here is the code:
public static final int DEVICE_ORIENTATION_PORTRAIT = 0;
public static final int DEVICE_ORIENTATION_INVERSE_PORTRAIT = 1;
public static final int DEVICE_ORIENTATION_LANDSCAPE = 2;
public static final int DEVICE_ORIENTATION_INVERSE_LANDSCAPE = 3;
private Camera.CameraInfo cameraInfo;
public volatile int deviceOrientation = DEVICE_ORIENTATION_PORTRAIT;
private FSDK.HTracker tracker;
public Matrix transform;
private int[] textures;
private Camera camera;
private SurfaceTexture surfaceTexture;
private boolean updateSurfaceTexture = false;
private FSDK.FSDK_Features[] trackingFeatures;
private MR.MaskFeatures maskCoords;
private int[] isMaskTexture1Created = new int[]{0};
private int[] isMaskTexture2Created = new int[]{0};
private int width;
private int height;
private ByteBuffer pixelBuffer;
private FSDK.HImage cameraImage = new FSDK.HImage();
private FSDK.FSDK_IMAGEMODE cameraImageMode = new FSDK.FSDK_IMAGEMODE();
private FSDK.HImage snapshotImage = new FSDK.HImage();
private FSDK.FSDK_IMAGEMODE snapshotImageMode = new FSDK.FSDK_IMAGEMODE();
private MainView mainView;
private MainActivity mainActivity;
private volatile boolean isResizeCalled = false;
private volatile boolean isResized = false;
public long IDs[] = new long[MR.MAX_FACES];
public long face_count[] = new long[1];
private long frameCount = 0;
private long startTime = 0;
private AtomicBoolean isTakingSnapshot = new AtomicBoolean(false);
public static final int[][] MASKS = new int[][]{
{R.raw.lips_pink, R.drawable.lips_pink, R.drawable.lips_pink_normal, MR.SHIFT_TYPE_NO},
{R.raw.lips_purple, R.drawable.lips_purple, R.drawable.lips_purple_normal, MR.SHIFT_TYPE_NO},
{R.raw.lips_red, R.drawable.lips_red, R.drawable.lips_red_normal, MR.SHIFT_TYPE_NO},
};
private int mask = 0;
private int maskLoaded = 0;
private volatile boolean isMaskChanged = false;
private boolean inPreview = false;
public void changeMask(int i) {
mask += i;
isMaskChanged = true;
}
public MainRenderer(MainView view) {
tracker = Application.tracker;
mainView = view;
mainActivity = (MainActivity) mainView.getContext();
trackingFeatures = new FSDK.FSDK_Features[MR.MAX_FACES];
for (int i = 0; i < MR.MAX_FACES; ++i) {
trackingFeatures[i] = new FSDK.FSDK_Features();
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
trackingFeatures[i].features[j] = new FSDK.TPoint();
}
}
maskCoords = new MR.MaskFeatures();
}
public void close() {
/*updateSurfaceTexture = false;
surfaceTexture.release();
camera.stopPreview();
camera.release();
camera = null;
deleteTex();*/
}
public void startCamera() {
if (inPreview) {
camera.stopPreview();
inPreview = false;
}
camera.release();
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
cameraInfo.facing = Camera.CameraInfo.CAMERA_FACING_FRONT;
} else {
cameraInfo.facing = Camera.CameraInfo.CAMERA_FACING_BACK;
}
camera = Camera.open(cameraInfo.facing);
final Camera.Size previewSize = camera.getParameters().getPreviewSize();
int rotation = mainActivity.getWindowManager().getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
camera.setDisplayOrientation(90);
new Thread() {
#Override
public void run() {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mainActivity.mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(previewSize.height, previewSize.width));
}
});
}
};
transform.setScale(-1, 1, previewSize.height / 2, 0);
break;
case Surface.ROTATION_90:
camera.setDisplayOrientation(0);
new Thread() {
#Override
public void run() {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mainActivity.mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(previewSize.width, previewSize.height));
}
});
}
};
transform.setScale(-1, 1, previewSize.width / 2, 0);
break;
case Surface.ROTATION_180:
camera.setDisplayOrientation(270);
new Thread() {
#Override
public void run() {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mainActivity.mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(previewSize.height, previewSize.width));
}
});
}
};
transform.setScale(-1, 1, previewSize.height / 2, 0);
break;
case Surface.ROTATION_270:
camera.setDisplayOrientation(180);
new Thread() {
#Override
public void run() {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mainActivity.mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(previewSize.width, previewSize.height));
}
});
}
};
transform.setScale(-1, 1, previewSize.width / 2, 0);
break;
}
try {
camera.setPreviewTexture(surfaceTexture);
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
inPreview = true;
}
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
Log.d(TAG, "surfaceCreated");
isResizeCalled = false;
isResized = false;
initTex();
loadMask(mask);
surfaceTexture = new SurfaceTexture(textures[0]);
surfaceTexture.setOnFrameAvailableListener(this);
int cameraId = 0;
boolean frontCameraFound = false;
cameraInfo = new Camera.CameraInfo();
cameraInfo.facing = Camera.CameraInfo.CAMERA_FACING_BACK;
camera = Camera.open(0);
transform = new Matrix();
final Camera.Size previewSize = camera.getParameters().getPreviewSize();
int rotation = mainActivity.getWindowManager().getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
camera.setDisplayOrientation(90);
new Thread() {
#Override
public void run() {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mainActivity.mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(previewSize.height, previewSize.width));
}
});
}
};
transform.setScale(-1, 1, previewSize.height / 2, 0);
break;
case Surface.ROTATION_90:
camera.setDisplayOrientation(0);
new Thread() {
#Override
public void run() {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mainActivity.mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(previewSize.width, previewSize.height));
}
});
}
};
transform.setScale(-1, 1, previewSize.width / 2, 0);
break;
case Surface.ROTATION_180:
camera.setDisplayOrientation(270);
new Thread() {
#Override
public void run() {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mainActivity.mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(previewSize.height, previewSize.width));
}
});
}
};
transform.setScale(-1, 1, previewSize.height / 2, 0);
break;
case Surface.ROTATION_270:
camera.setDisplayOrientation(180);
new Thread() {
#Override
public void run() {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mainActivity.mainLayout.setLayoutParams(new RelativeLayout.LayoutParams(previewSize.width, previewSize.height));
}
});
}
};
transform.setScale(-1, 1, previewSize.width / 2, 0);
break;
}
try {
camera.setPreviewTexture(surfaceTexture);
} catch (IOException e) {
e.printStackTrace();
}
GLES11.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
private byte[] readBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int bufferSize = 16384;
byte[] buffer = new byte[bufferSize];
int len;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}
return byteBuffer.toByteArray();
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
public void loadMask(int maskNumber) {
GLES11.glDisable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
Log.d(TAG, "Loading mask...");
int[] mask = MASKS[maskNumber];
if (isMaskTexture1Created[0] > 0) {
GLES11.glDeleteTextures(1, textures, 1);
}
if (isMaskTexture2Created[0] > 0) {
GLES11.glDeleteTextures(1, textures, 2);
}
isMaskTexture1Created[0] = 0;
isMaskTexture2Created[0] = 0;
InputStream stream = mainView.getResources().openRawResource(mask[0]);
int res = MR.LoadMaskCoordsFromStream(stream, maskCoords);
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (res != FSDK.FSDKE_OK) {
Log.e(TAG, "Error loading mask coords from stream: " + res);
GLES11.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
return;
}
BitmapFactory.Options bitmapDecodingOptions = new BitmapFactory.Options();
bitmapDecodingOptions.inScaled = false;
FSDK.HImage img1 = new FSDK.HImage();
if (mask[1] == -1) {
FSDK.CreateEmptyImage(img1);
} else {
stream = mainView.getResources().openRawResource(mask[1]);
byte[] data = null;
try {
data = readBytes(stream);
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (data != null) {
res = FSDK.LoadImageFromPngBufferWithAlpha(img1, data, data.length);
Log.d(TAG, "Load mask image of size " + data.length + " with result " + res);
int[] w = new int[]{0};
int[] h = new int[]{0};
FSDK.GetImageWidth(img1, w);
FSDK.GetImageHeight(img1, h);
Log.d(TAG, "Mask image size: " + w[0] + " x " + h[0]);
} else {
Log.w(TAG, "Error loading mask image, using empty image");
FSDK.CreateEmptyImage(img1);
}
}
FSDK.HImage img2 = new FSDK.HImage();
if (mask[2] == -1) {
FSDK.CreateEmptyImage(img2);
} else {
stream = mainView.getResources().openRawResource(mask[2]);
byte[] data = null;
try {
data = readBytes(stream);
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (data != null) {
res = FSDK.LoadImageFromPngBufferWithAlpha(img2, data, data.length);
Log.d(TAG, "Load mask normal image of size " + data.length + " with result " + res);
int[] w = new int[]{0};
int[] h = new int[]{0};
FSDK.GetImageWidth(img2, w);
FSDK.GetImageHeight(img2, h);
Log.d(TAG, "Mask normal image size: " + w[0] + " x " + h[0]);
} else {
Log.w(TAG, "Error loading mask normal image, using empty image");
FSDK.CreateEmptyImage(img2);
}
}
res = MR.LoadMask(img1, img2, textures[1], textures[2], isMaskTexture1Created, isMaskTexture2Created);
FSDK.FreeImage(img1);
FSDK.FreeImage(img2);
Log.d(TAG, "Mask loaded with result " + res + " texture1Created:" + isMaskTexture1Created[0] + " texture2Created:" + isMaskTexture2Created[0]);
Log.d(TAG, "Mask textures: " + textures[1] + " " + textures[2]);
GLES11.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
}
public void onDrawFrame(GL10 unused) {
GLES11.glClear(GLES11.GL_COLOR_BUFFER_BIT);
if (!isResized) {
return;
}
synchronized (this) {
if (updateSurfaceTexture) {
surfaceTexture.updateTexImage();
updateSurfaceTexture = false;
}
}
if (isMaskChanged) {
maskLoaded = mask;
loadMask(mask);
isMaskChanged = false;
}
int rotation;
if (cameraInfo.facing == 1) {
rotation = 1;
} else {
rotation = -1;
}
int res = MR.DrawGLScene(textures[0], 0, trackingFeatures, rotation, MR.SHIFT_TYPE_NO, textures[1], textures[2], maskCoords, 0, 0, width, height);
if (FSDK.FSDKE_OK != res) {
Log.e(TAG, "Error in the first MR.DrawGLScene call: " + res);
}
GLES11.glReadPixels(0, 0, width, height, GLES11.GL_RGBA, GLES11.GL_UNSIGNED_BYTE, pixelBuffer);
face_count[0] = 0;
if (cameraInfo.facing == 1) {
processCameraImageFront();
}
if (cameraInfo.facing == 0) {
processCameraImageRear();
}
res = MR.DrawGLScene(textures[0], (int) face_count[0], trackingFeatures, rotation, MASKS[maskLoaded][3], textures[1], textures[2], maskCoords, isMaskTexture1Created[0], isMaskTexture2Created[0], width, height);
if (FSDK.FSDKE_OK != res) {
Log.e(TAG, "Error in the second MR.DrawGLScene call: " + res);
}
if (isTakingSnapshot.compareAndSet(true, false)) {
GLES11.glReadPixels(0, 0, width, height, GLES11.GL_RGBA, GLES11.GL_UNSIGNED_BYTE, pixelBuffer);
snapshotImageMode.mode = FSDK.FSDK_IMAGEMODE.FSDK_IMAGE_COLOR_32BIT;
res = FSDK.LoadImageFromBuffer(snapshotImage, pixelBuffer.array(), width, height, width * 4, snapshotImageMode);
if (FSDK.FSDKE_OK != res) {
Log.e(TAG, "Error loading snapshot image to FaceSDK: " + res);
} else {
FSDK.MirrorImage(snapshotImage, false);
String galleryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath();
final String filename = galleryPath + "/MirrorRealityDemo" + System.currentTimeMillis() + ".png";
res = FSDK.SaveImageToFile(snapshotImage, filename);
Log.d(TAG, "saving snapshot to " + filename);
FSDK.FreeImage(snapshotImage);
if (FSDK.FSDKE_OK == res) {
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(filename);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
mainActivity.sendBroadcast(mediaScanIntent);
Toast.makeText(mainActivity, "Saved successfully", Toast.LENGTH_SHORT).show();
}
});
}
}
}
++frameCount;
long timeCurrent = System.currentTimeMillis();
if (startTime == 0) startTime = timeCurrent;
long diff = timeCurrent - startTime;
if (diff >= 3000) {
final float fps = frameCount / (diff / 1000.0f);
frameCount = 0;
startTime = 0;
final TextView fpsTextView = mainActivity.fpsTextView();
mainActivity.fpsTextView().post(new Runnable() {
#Override
public void run() {
if (!mainActivity.isFinishing()) {
fpsTextView.setText(fps + " FPS");
}
}
});
}
}
private void processCameraImageFront() {
for (int i = 0; i < MR.MAX_FACES; ++i) {
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
trackingFeatures[i].features[j].x = 0;
trackingFeatures[i].features[j].y = 0;
}
}
cameraImageMode.mode = FSDK.FSDK_IMAGEMODE.FSDK_IMAGE_COLOR_32BIT;
int res = FSDK.LoadImageFromBuffer(cameraImage, pixelBuffer.array(), width, height, width * 4, cameraImageMode);
if (FSDK.FSDKE_OK != res) {
Log.e(TAG, "Error loading camera image to FaceSDK: " + res);
return;
}
int[] widthByReference = new int[1];
int[] heightByReference = new int[1];
FSDK.GetImageWidth(cameraImage, widthByReference);
FSDK.GetImageHeight(cameraImage, heightByReference);
int width = widthByReference[0];
int height = heightByReference[0];
int rotation = 0;
if (deviceOrientation == DEVICE_ORIENTATION_INVERSE_PORTRAIT) {
rotation = 2;
} else if (deviceOrientation == DEVICE_ORIENTATION_LANDSCAPE) {
rotation = 3;
} else if (deviceOrientation == DEVICE_ORIENTATION_INVERSE_LANDSCAPE) {
rotation = 1;
}
if (rotation > 0) {
FSDK.HImage rotated = new FSDK.HImage();
FSDK.CreateEmptyImage(rotated);
FSDK.RotateImage90(cameraImage, rotation, rotated);
FSDK.FeedFrame(tracker, 0, rotated, face_count, IDs);
FSDK.FreeImage(rotated);
} else {
FSDK.FeedFrame(tracker, 0, cameraImage, face_count, IDs);
}
for (int i = 0; i < (int) face_count[0]; ++i) {
FSDK.GetTrackerFacialFeatures(tracker, 0, IDs[i], trackingFeatures[i]);
if (rotation > 0) {
if (rotation == 1) {
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
int x = trackingFeatures[i].features[j].x;
trackingFeatures[i].features[j].x = trackingFeatures[i].features[j].y;
trackingFeatures[i].features[j].y = height - 1 - x;
}
} else if (rotation == 2) {
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
trackingFeatures[i].features[j].x = width - 1 - trackingFeatures[i].features[j].x;
trackingFeatures[i].features[j].y = height - 1 - trackingFeatures[i].features[j].y;
}
} else {
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
int x = trackingFeatures[i].features[j].x;
trackingFeatures[i].features[j].x = width - 1 - trackingFeatures[i].features[j].y;
trackingFeatures[i].features[j].y = x;
}
}
}
}
FSDK.FreeImage(cameraImage);
}
private void processCameraImageRear() {
for (int i = 0; i < MR.MAX_FACES; ++i) {
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
trackingFeatures[i].features[j].x = 0;
trackingFeatures[i].features[j].y = 0;
}
}
cameraImageMode.mode = FSDK.FSDK_IMAGEMODE.FSDK_IMAGE_COLOR_32BIT;
int res = FSDK.LoadImageFromBuffer(cameraImage, pixelBuffer.array(), width, height, width * 4, cameraImageMode);
if (FSDK.FSDKE_OK != res) {
Log.e(TAG, "Error loading camera image to FaceSDK: " + res);
return;
}
int[] widthByReference = new int[1];
int[] heightByReference = new int[1];
FSDK.GetImageWidth(cameraImage, widthByReference);
FSDK.GetImageHeight(cameraImage, heightByReference);
int width = widthByReference[0];
int height = heightByReference[0];
/*int rotation = 0;
if (deviceOrientation == DEVICE_ORIENTATION_PORTRAIT) {
rotation = 0;
} else if (deviceOrientation == DEVICE_ORIENTATION_INVERSE_PORTRAIT) {
rotation = 2;
} else if (deviceOrientation == DEVICE_ORIENTATION_LANDSCAPE) {
rotation = 3;
} else if (deviceOrientation == DEVICE_ORIENTATION_INVERSE_LANDSCAPE) {
rotation = 1;
}*/
int rotation = 1;
if (rotation > 0) {
FSDK.HImage rotated = new FSDK.HImage();
FSDK.CreateEmptyImage(rotated);
FSDK.FeedFrame(tracker, 0, rotated, face_count, IDs);
FSDK.FreeImage(rotated);
} else {
FSDK.FeedFrame(tracker, 0, cameraImage, face_count, IDs);
}
for (int i = 0; i < (int) face_count[0]; ++i) {
FSDK.GetTrackerFacialFeatures(tracker, 0, IDs[i], trackingFeatures[i]);
if (rotation > 0) {
if (rotation == 1) {
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
int x = trackingFeatures[i].features[j].x;
trackingFeatures[i].features[j].x = trackingFeatures[i].features[j].y;
trackingFeatures[i].features[j].y = height - 1 - x;
}
} else if (rotation == 2) {
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
trackingFeatures[i].features[j].x = width - 1 - trackingFeatures[i].features[j].x;
trackingFeatures[i].features[j].y = height - 1 - trackingFeatures[i].features[j].y;
}
} else {
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
int x = trackingFeatures[i].features[j].x;
trackingFeatures[i].features[j].x = width - 1 - trackingFeatures[i].features[j].y;
trackingFeatures[i].features[j].y = x;
}
}
}
}
FSDK.FreeImage(cameraImage);
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
Log.d(TAG, "surfaceChanged");
if (!isResizeCalled) {
isResizeCalled = true;
mainView.resizeForPerformance(width, height);
return;
}
GLES11.glViewport(0, 0, width, height);
Camera.Parameters param = camera.getParameters();
List<Camera.Size> psize = param.getSupportedPreviewSizes();
if (psize.size() > 0) {
int i = 0;
int optDistance = Integer.MAX_VALUE;
Log.d(TAG, "Choosing preview resolution closer to " + width + " x " + height);
double neededScale = height / (double) width;
for (int j = 0; j < psize.size(); ++j) {
double scale = psize.get(j).width / (double) psize.get(j).height;
int distance = (int) (10000 * Math.abs(scale - neededScale));
Log.d(TAG, "Choosing preview resolution, probing " + psize.get(j).width + " x " + psize.get(j).height + " distance: " + distance);
if (distance < optDistance) {
i = j;
optDistance = distance;
} else if (distance == optDistance) {
if ((psize.get(i).width < 300 || psize.get(i).height < 300)
&& psize.get(j).width > psize.get(i).width && psize.get(j).height > psize.get(i).height) {
i = j;
}
}
}
Log.d(TAG, "Using optimal preview size: " + psize.get(i).width + " x " + psize.get(i).height);
param.setPreviewSize(psize.get(i).width, psize.get(i).height);
int viewportHeight = (int) (width * (psize.get(i).width * 1.0f / psize.get(i).height));
GLES11.glViewport(0, 0, width, viewportHeight);
this.width = width;
this.height = viewportHeight;
pixelBuffer = ByteBuffer.allocateDirect(this.width * this.height * 4).order(ByteOrder.nativeOrder());
}
camera.setParameters(param);
camera.startPreview();
inPreview = true;
isResized = true;
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
private void initTex() {
textures = new int[3];
GLES11.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
GLES11.glEnable(GL10.GL_TEXTURE_2D);
GLES11.glGenTextures(3, textures, 0);
GLES11.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
GLES11.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES11.GL_TEXTURE_WRAP_S, GLES11.GL_CLAMP_TO_EDGE);
GLES11.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES11.GL_TEXTURE_WRAP_T, GLES11.GL_CLAMP_TO_EDGE);
GLES11.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES11.GL_TEXTURE_MIN_FILTER, GLES11.GL_NEAREST);
GLES11.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES11.GL_TEXTURE_MAG_FILTER, GLES11.GL_NEAREST);
}
private void deleteTex() {
GLES11.glDeleteTextures(3, textures, 0);
}
public synchronized void onFrameAvailable(SurfaceTexture st) {
updateSurfaceTexture = true;
mainView.requestRender();
}
public synchronized void snapshot() {
isTakingSnapshot.set(true);
}
I really think that i've written something wrong but i can't figure it so can anyone see my code or if he knows anything about the preview that is being mirrored in my case can he answer please!
Any type of help is needed and appreciated! Thank you.
Basically I have been making a simple game in which I now want to create collision detection between the Player and the Enemy. I have made both a class of the player and the enemy and then also a separate GameView class. My issue is that there is simply no collision happening and I just don't understand why, I have changed the code various times but I still can't seem to crack it. I will leave my code below and if anyone sees where I have gone wrong it would be great help. Thank you.
GameView Class:
public class GameView extends SurfaceView implements Runnable {
Canvas canvas;
SurfaceHolder surfaceHolder;
Thread thread = null;
volatile boolean playing;
Paint paint;
Context context;
Player player;
int screenX, screenY, numberOfEnemies = 4, distanceBetweenEnemies;
int enemyX [] = new int[numberOfEnemies];
int enemyY [] = new int[numberOfEnemies];
private boolean paused = true;
Enemy enemy;
Enemy [] enemies;
Random random;
Rect [] enemyRectangle;
public GameView (Context context, int x, int y) {
super(context);
this.context = context;
surfaceHolder = getHolder();
paint = new Paint();
thread = new Thread();
screenX = x;
screenY = y;
player = new Player (context, screenX, screenY);
enemies = new Enemy[numberOfEnemies];
enemyRectangle = new Rect[numberOfEnemies];
enemy = new Enemy (context, screenX);
distanceBetweenEnemies = screenX * 3 / 4;
for (int i = 0; i < numberOfEnemies; i ++) {
enemies[i] = new Enemy(context, screenX);
enemyX[i] = screenX / 2 - enemy.getEnemyBitmap().getWidth() / 2 + i * distanceBetweenEnemies;
random = new Random();
enemyY[i] = random.nextInt(screenY - enemy.getEnemyBitmap().getHeight() / 2);
}
}
#Override
public void run() {
while (playing) {
draw();
if(!paused){
update();
}
}
}
private void draw () {
if (surfaceHolder.getSurface().isValid()) {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.argb(255, 26, 128, 182));
canvas.drawBitmap(player.getPlayerBitmap(), player.getX(), player.getY(), null);
for (int i = 0; i < numberOfEnemies; i ++) {
canvas.drawBitmap(enemies[i].getEnemyBitmap(), enemyX[i], enemyY[i], null);
enemyRectangle [i] = new Rect(enemyX[i], enemyY[i], enemy.getEnemyBitmap().getWidth(),
enemy.getEnemyBitmap().getHeight());
enemyX[i] += enemy.getEnemySpeed();
}
update ();
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
private void update () {
player.updatePlayerPosition();
player.noLeaveScreen();
for (int i = 0; i < numberOfEnemies; i ++) {
if (enemyX[i] < 0 - enemy.getEnemyBitmap().getWidth()) {
enemyY[i] = random.nextInt(screenY);
enemyRectangle [i] = new Rect(enemyX[i], enemyY[i], enemy.getEnemyBitmap().getWidth(),
enemy.getEnemyBitmap().getHeight());
enemyX[i] += numberOfEnemies * distanceBetweenEnemies;
} else {
enemyX[i] += enemy.getEnemySpeed();
}
if (Rect.intersects(player.getPlayerRectangle(), enemyRectangle[i])) {
Log.e("COLLISION:", "Detected");
enemyX[i] = - 200;
}
}
}
public void pause () {
playing = false;
try {
thread.join();
} catch (InterruptedException e) {
Log.e("Error:", "joining thread");
}
}
public void resume () {
playing = true;
thread = new Thread(this);
thread.start();
}
#Override
public boolean onTouchEvent (MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
player.playerJump();
break;
}
return true;
}
}
Player Class:
public class Player {
Bitmap playerBitmap;
Rect playerRectangle;
int x, y, playerJumpSpeed, gravity, screenY;
boolean playerIsMoving;
public Player (Context context, int screenX, int screenY) {
this.screenY = screenY;
gravity = 2;
playerBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
x = screenX/2 - playerBitmap.getWidth()/2;
y = screenY/2 - playerBitmap.getHeight()/2;
playerRectangle = new Rect(x, y, playerBitmap.getWidth(), playerBitmap.getHeight());
playerJumpSpeed = - 1000;
playerIsMoving = true;
}
public void updatePlayerPosition () {
while (playerIsMoving) {
y += gravity;
break;
}
}
public void playerJump () {
while (playerIsMoving) {
y += playerJumpSpeed;
break;
}
}
public void noLeaveScreen () {
if (y < 0) {
playerJumpSpeed = 0;
} else {
playerJumpSpeed = - 40;
}
if (getY() > (screenY - playerBitmap.getHeight())) {
gravity = 0;
} else {
gravity = 2;
}
}
public int getX () {
return x;
}
public int getY () {
return y;
}
public Bitmap getPlayerBitmap () {
return playerBitmap;
}
public Rect getPlayerRectangle () {
return playerRectangle;
}
}
Enemy Class:
public class Enemy {
Bitmap enemyBitmap;
int enemySpeed, screenX;
boolean isEnemyMoving;
Random random;
public Enemy (Context context, int screenX) {
this.screenX = screenX;
enemyBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
random = new Random();
isEnemyMoving = true;
enemySpeed = - 3;
}
public int getEnemySpeed () {
return enemySpeed;
}
public Bitmap getEnemyBitmap () {
return enemyBitmap;
}
}
There are the classes, any help appreciated!
I am making an app where balls fall from the top of the screen to the bottom of the screen, and the user has to touch a certain area to make the balls disappear. However, when the balls fall, they appear to stutter as the fall down the screen. Here is the entire code for the project:
public class GameActivity extends Activity implements View.OnTouchListener {
MyBringBack ourSurfaceView;
Paint p;
float x, y, secondX, secondY;
int firstRun;
Bitmap green, red, blue, purple, white;
int currentColor;
ArrayList<Ball> balls = new ArrayList<>();
Paint buttonPaint;
Boolean thingFirstRun;
int score;
Model model;
int cHeight, cWidth;
int nextBallSpeed;
int totalBalls;
int countBalls;
int buttonState = 0;
public final static int BUTTON_NONE = 0;
public final static int BUTTON_LEFT = 1;
public final static int BUTTON_RIGHT = 2;
public final static int BUTTON_BOTH = 3;
class Ball {
public Ball(int x, int y, int s, int color, Bitmap b) {
xCord = x;
yCord = y;
speed = s;
this.color = color;
passedLineYet = false;
bitmap = b;
}
public int xCord;
public int yCord;
public int speed;
public int color;
public boolean passedLineYet;
public Bitmap bitmap;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
red = BitmapFactory.decodeResource(getResources(), R.drawable.redcircle);
blue = BitmapFactory.decodeResource(getResources(), R.drawable.bluecircle);
green = BitmapFactory.decodeResource(getResources(), R.drawable.greencircle);
purple = BitmapFactory.decodeResource(getResources(), R.drawable.purplecircle);
white = BitmapFactory.decodeResource(getResources(), R.drawable.white);
secondX = secondY = -1;
cHeight = 0;
cWidth = 0;
countBalls = 0;
nextBallSpeed = 60;
p = new Paint();
p.setColor(Color.WHITE);
p.setTextSize(200);
ourSurfaceView = new MyBringBack(this);
ourSurfaceView.setOnTouchListener(this);
setContentView(ourSurfaceView);
model = new Model();
score = 0;
(new Thread(model)).start();
thingFirstRun = false;
currentColor = Color.GREEN;
buttonPaint = new Paint();
buttonPaint.setColor(currentColor);
buttonPaint.setStrokeWidth(10);
buttonPaint.setStyle(Paint.Style.FILL);
firstRun = 0;
}
public boolean correctColor(Ball b) {
if (currentColor == b.color) {
return true;
}
return false;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
return true;
}
#Override
protected void onPause() {
super.onPause();
ourSurfaceView.pause();
}
#Override
protected void onResume() {
super.onResume();
ourSurfaceView.resume();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
try {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
float xEvent = event.getX(event.getPointerId(event.getActionIndex()));
float yEvent = event.getY(event.getPointerId(event.getActionIndex()));
if (yEvent > cHeight / 4 * 3) {
if (xEvent < cWidth / 2) {
buttonState |= BUTTON_LEFT;
}
if (xEvent > cWidth / 2) {
buttonState |= BUTTON_RIGHT;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP:
try {
xEvent = event.getX(event.getPointerId(event.getActionIndex()));
yEvent = event.getY(event.getPointerId(event.getActionIndex()));
} catch (Exception e) {
xEvent = event.getX();
yEvent = event.getY();
}
if (yEvent > cHeight / 4 * 3) {
if (xEvent < cWidth / 2) {
buttonState &= ~BUTTON_LEFT;
}
if (xEvent > cWidth / 2) {
buttonState &= ~BUTTON_RIGHT;
}
}
break;
}
switch (buttonState) {
case BUTTON_LEFT:
currentColor = Color.RED;
break;
case BUTTON_RIGHT:
currentColor = Color.BLUE;
break;
case BUTTON_BOTH:
currentColor = Color.MAGENTA;
break;
case BUTTON_NONE:
currentColor = Color.GREEN;
break;
}
buttonPaint.setColor(currentColor);
Log.v("BUTTON STATE", buttonState + "");
Log.v("BUTTON COLOR", currentColor + "");
return true;
} catch (Exception e) {
}
return true;
}
public class Model extends Thread implements Runnable {
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000 / 240);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (countBalls % nextBallSpeed == 0) {
int temp = (int) (Math.random() * 4);
if (temp == 0) {
balls.add(new Ball((int) (Math.random() * (cWidth - red.getWidth())), 0 - red.getHeight(), cHeight / 800, Color.RED, red));
} else if (temp == 1) {
balls.add(new Ball((int) (Math.random() * (cWidth - red.getWidth())), 0 - green.getHeight(), cHeight / 800, Color.GREEN, green));
} else if (temp == 2) {
balls.add(new Ball((int) (Math.random() * (cWidth - blue.getWidth())), 0 - blue.getHeight(), cHeight / 800, Color.BLUE, blue));
} else if (temp == 3) {
balls.add(new Ball((int) (Math.random() * (cWidth - purple.getWidth())), 0 - purple.getHeight(), cHeight / 800, Color.MAGENTA, purple));
}
totalBalls++;
}
if (totalBalls < 10) {
nextBallSpeed = 30;
} else if (totalBalls < 30) {
nextBallSpeed = 25;
} else if (totalBalls < 50) {
nextBallSpeed = 20;
} else if (totalBalls < 80) {
nextBallSpeed = 15;
} else if (totalBalls < 150) {
nextBallSpeed = 10;
} else {
nextBallSpeed = 5;
}
for (int i = 0; i < balls.size(); i++) {
int h = cHeight;
balls.get(i).yCord += balls.get(i).speed;
}
for (int i = 0; i < balls.size(); i++) {
try {
if (balls.get(i).yCord + green.getHeight() > ((double) cHeight * .75) && !balls.get(i).passedLineYet) {
balls.get(i).passedLineYet = true;
boolean b = correctColor(balls.get(i));
if (b) {
balls.remove(i);
score++;
}
if (!b) {
}
} else if (balls.get(i).yCord > cHeight) {
balls.remove(i);
score -= 5;
}
} catch (Exception ignored) {
}
}
countBalls++;
}
}
public boolean correctColor(Ball b) {
if (currentColor == b.color) {
return true;
}
return false;
}
}
public class MyBringBack extends SurfaceView implements Runnable {
SurfaceHolder ourHolder;
Thread ourThread = null;
boolean isRunning = false;
public MyBringBack(Context context) {
super(context);
ourHolder = getHolder();
}
public void pause() {
isRunning = false;
while (true) {
try {
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
ourThread = null;
}
public void resume() {
isRunning = true;
ourThread = new Thread(this);
ourThread.start();
}
#Override
public void run() {
while (isRunning) {
try {
Thread.sleep(1000 / 240);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!ourHolder.getSurface().isValid()) {
continue;
}
//NE
Bitmap tempCanvasBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas tempCanvas = new Canvas();
tempCanvas.setBitmap(tempCanvasBitmap);
//NEND
//Canvas canvas = ourHolder.lockCanvas();
tempCanvas.drawColor(Color.BLACK);
if (firstRun == 0) {
cHeight = tempCanvas.getHeight();
cWidth = tempCanvas.getWidth();
red = getResizedBitmap(red, tempCanvas.getWidth() / 12, tempCanvas.getWidth() / 12);
green = getResizedBitmap(green, tempCanvas.getWidth() / 12, tempCanvas.getWidth() / 12);
blue = getResizedBitmap(blue, tempCanvas.getWidth() / 12, tempCanvas.getWidth() / 12);
purple = getResizedBitmap(purple, tempCanvas.getWidth() / 12, tempCanvas.getWidth() / 12);
white = getResizedBitmap(white, cHeight / 4 * 3, cWidth / 20);
firstRun = 1;
totalBalls = 0;
}
//canvas.drawBitmap(white, );
tempCanvas.drawRect(0, tempCanvas.getHeight() * 3 / 4, tempCanvas.getWidth(), tempCanvas.getHeight(), buttonPaint);
for (int i = 0; i < balls.size(); i++) {
try {
tempCanvas.drawBitmap(balls.get(i).bitmap, balls.get(i).xCord, balls.get(i).yCord, null);
} catch (Exception ignored) {
}
}
Rect r = new Rect();
p.getTextBounds(score + "", 0, (score + "").length(), r);
tempCanvas.drawText(score + "", cWidth - r.width() - 20, r.height() + 20, p);
Canvas canvas = ourHolder.lockCanvas();
canvas.drawBitmap(tempCanvasBitmap, 0, 0, p);
ourHolder.unlockCanvasAndPost(canvas);
}
}
}
public static Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
}
I have created animations before, but without the use of a Runnable (all code in the onDraw() method). Perhaps the issue is with that.
Does anyone know why this stuttering might be occurring?
Use This:
Add the class member fields, replace your run(), and add primeCanvas() method.
boolean isPrimed = false;
Canvas canvas;
#Override
public void run() {
while(isRunning) {
if (!ourHolder.getSurface().isValid())
continue;
canvas = ourHolder.lockCanvas();
if(!isPrimed)
primeCanvas();
canvas.drawColor(Color.BLACK);
canvas.drawRect(0, canvas.getHeight() * 3 / 4, canvas.getWidth(), canvas.getHeight(), buttonPaint);
for(int i = 0; i < balls.size(); i ++)
canvas.drawBitmap(balls.get(i).bitmap, balls.get(i).xCord, balls.get(i).yCord, null);
Rect r = new Rect();
p.getTextBounds(score + "", 0, (score + "").length(), r);
canvas.drawText(score + "", cWidth - r.width() - 20, r.height() + 20, p);
ourHolder.unlockCanvasAndPost(canvas);
}
}
private void primeCanvas() {
cHeight = canvas.getHeight();
cWidth = canvas.getWidth();
red = getResizedBitmap(red, canvas.getWidth()/12, canvas.getWidth()/12);
green = getResizedBitmap(green, canvas.getWidth()/12, canvas.getWidth()/12);
blue = getResizedBitmap(blue, canvas.getWidth()/12, canvas.getWidth()/12);
purple = getResizedBitmap(purple, canvas.getWidth()/12, canvas.getWidth()/12);
white = getResizedBitmap(white, cHeight / 4 * 3, cWidth / 20);
firstRun = 1;
totalBalls = 0;
}
I have a game that displays circles randomly on the screen. The circles can be green or red at random. If you touch a red circle something happens; if you touch a green circle something happens; but what if you wanted to check if the green circle was displayed and a user did not click it? Here is my code:
public class DrawingView extends View{
public DrawingView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
RectF rectf = new RectF(0, 0, 200, 0);
private static final int w = 100;
public static int lastColor = Color.BLACK;
private final Random random = new Random();
private final Paint paint = new Paint();
private final int radius = 230;
private final Handler handler = new Handler();
public static int redColor = Color.RED;
public static int greenColor = Color.GREEN;
int randomWidth = 0;
int randomHeight = 0;
public static int addPoints = 0;
public static int savedScore;
public static List<String> a = new ArrayList<String>();
public static String[] savedScores = new String[a.size()];
Paint red;
public static int howManyPoints;
public static int highestScore = 0;
boolean isTouched;
Thread newThread = new Thread();
private final Runnable updateCircle = new Runnable() {
#Override
public void run() {
lastColor = random.nextInt(2) == 1 ? redColor : greenColor;
paint.setColor(lastColor);
if(lastColor == greenColor){
isTouched = false;
}
if(addPoints < 10){
handler.postDelayed(this, 850);
}
if(addPoints > 9 && addPoints < 30){
handler.postDelayed(this,700);
}
if(addPoints > 29){
handler.postDelayed(this, 600);
}
if(addPoints > 50){
handler.postDelayed(this, 450);
}
if(addPoints > 100){
handler.postDelayed(this, 400);
}
postInvalidate();
}
};
public void what(){
try {
newThread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(isTouched == false){
howManyPoints = addPoints;
handler.removeCallbacks(updateCircle);
lastColor = redColor;
addPoints = 0;
Intent i = new Intent(this.getContext(), YouFailed.class);
this.getContext().startActivity(i);
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
handler.post(updateCircle);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
handler.removeCallbacks(updateCircle);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// your other stuff here
Paint back = new Paint();
back.setColor(Color.BLACK);
Rect background = new Rect();
background.set(0, 0, canvas.getWidth(),canvas.getHeight() );
canvas.drawRect(background, back);
Paint newPaint = new Paint();
newPaint.setColor(Color.BLUE);
newPaint.setTextSize(60);
canvas.drawText("Beta v2", 10, 60, newPaint);
if(random == null){
randomWidth =(int) (random.nextInt(Math.abs(getWidth()-radius/2)) + radius/2f);
randomHeight = (random.nextInt((int)Math.abs((getHeight()-radius/2 + radius/2f))));
}else {
randomWidth =(int) (random.nextInt(Math.abs(getWidth()-radius/2)) + radius/2f);
randomHeight = (random.nextInt((int)Math.abs((getHeight()-radius/2 + radius/2f))));
}
canvas.drawCircle(randomWidth, randomHeight, radius, paint);
what();
red = new Paint();
red.setColor(Color.BLUE);
red.setTextSize(150);
canvas.drawText("" + addPoints, 500, 1350, red);
}
#SuppressWarnings("deprecation")
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
int x = (int) event.getX();
int y = (int) event.getY();
if(isInsideCircle(x, y) == true){
//Do your things here
if(lastColor == redColor){
//saveScore();
howManyPoints = addPoints;
if(howManyPoints > highestScore){
highestScore = howManyPoints;
}
handler.removeCallbacks(updateCircle);
lastColor = redColor;
addPoints = 0;
Intent i = new Intent(this.getContext(), YouFailed.class);
this.getContext().startActivity(i);
}
if(lastColor == greenColor){
addPoints++;
isTouched = true;
}
}else {
}
}
return false;
}
public void saveScore() {
a.add("" + addPoints);
//if(Integer.parseInt(savedScores[1]) < addPoints){
//savedScores[2] = savedScores[1];
//int x = Integer.parseInt(savedScores[1]);
//x = addPoints;
//}
}
public boolean isInsideCircle(int x, int y){
if ((((x - randomWidth)*(x - randomWidth)) + ((y - randomHeight)*(y - randomHeight))) < ((radius)*(radius))){
return true;
}
return false;
}
}
Just add a boolean hasBeenClicked that is false and becomes true when the user touches it