I want to make a sprite\bitmap jump using only android (no game engines). I wasn't able to find tutorials on how to do so in android using only canvas and views, but I did find a tutorial for xna(http://www.xnadevelopment.com/tutorials/thewizardjumping/thewizardjumping.shtml), and I tried to recreate it with the tools android offers. I was able to make the character move left and right using the tutorial code but making it jump just won't work.
this is my sprite class:
package com.example.spiceup;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.view.KeyEvent;
import android.widget.Toast;
public class Sprite {
enum State
{
Walking, Standing, Jumping
}
State mCurrentState = State.Standing;
Point mDirection;
int mSpeed = 0;
Context cc;
int mPreviousKeyboardState;
private String spriteName;
Bitmap sprite;
private int rows;
private int rows2;
int START_POSITION_X = 125;
int START_POSITION_Y = 245;
int SPRITE_SPEED = 6;
int MOVE_UP = -1;
int MOVE_DOWN = 1;
int MOVE_LEFT = -1;
int MOVE_RIGHT = 1;
Point mStartingPosition;
int aCurrentKeyboardState;
private float mScale = 1.0f;
Point Position;
public Sprite(String name,Bitmap sprite) {
this.sprite=sprite;
this.spriteName=name;
Position=new Point(150,150);
mStartingPosition=new Point(150,150);
mDirection=new Point(0,0);
}
public void Update()
{
UpdateMovement(aCurrentKeyboardState);
UpdateJump(aCurrentKeyboardState);
}
public void setkeyboard(int keyboard){
aCurrentKeyboardState = keyboard;
}
public void setLastKeyboard(int keyboard){
mPreviousKeyboardState = keyboard;
}
private void UpdateMovement(int aCurrentKeyboardState)
{
if (mCurrentState == State.Walking)
{
mSpeed = 0;
mDirection.x = 0;
if (aCurrentKeyboardState==KeyEvent.KEYCODE_A)
{
mSpeed = SPRITE_SPEED;
mDirection.x = MOVE_LEFT;
}
else if(aCurrentKeyboardState==KeyEvent.KEYCODE_D)
{
mSpeed = SPRITE_SPEED;
mDirection.x= MOVE_RIGHT;
}
Position.x += mDirection.x * mSpeed;
}
}
private void UpdateJump(int aCurrentKeyboardState)
{
if (mCurrentState == State.Walking)
{
if (aCurrentKeyboardState==KeyEvent.KEYCODE_SPACE && mPreviousKeyboardState!=KeyEvent.KEYCODE_SPACE)
{
Jump();
}
}
if (mCurrentState == State.Jumping)
{
if (mStartingPosition.y - Position.y> 150)
{
Position.y += mDirection.y * mSpeed;
mDirection.y = MOVE_DOWN;
}
if (Position.y > mStartingPosition.y)
{
Position.y = mStartingPosition.y;
mCurrentState = State.Walking;
}
}
}
private void Jump()
{
if (mCurrentState != State.Jumping)
{
mCurrentState = State.Jumping;
mStartingPosition = Position;
mDirection.y = MOVE_UP;
mSpeed = 6;
Position.y += mDirection.y * mSpeed;
}
}
public void Draw(Canvas c)
{
c.drawBitmap(sprite, Position.x,Position.y, null);
}
public void setmCurrentState(State mCurrentState) {
this.mCurrentState = mCurrentState;
}
}
this is the surfaceview:
import com.example.spiceup.Sprite.State;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView {
Context cc;
Bitmap Sprite;
Sprite sprite2;
Handler handlerAnimation100;
private GameLoopThread gameLoopThread;
private SurfaceHolder holder;
public GameView(Context c) {
// TODO Auto-generated constructor stub
super(c);
gameLoopThread = new GameLoopThread(this);
this.cc=c;
this.Sprite=BitmapFactory.decodeResource(getResources(), R.drawable.walk1);
this.Sprite=Bitmap.createScaledBitmap(Sprite, Sprite.getWidth()*2, Sprite.getHeight()*2, false);
sprite2=new Sprite("Spicy",Sprite);
this.requestFocus();
this.setFocusableInTouchMode(true);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
sprite2.Update();
sprite2.Draw(canvas);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
sprite2.setkeyboard(keyCode);
sprite2.setmCurrentState(State.Walking);
return false;
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
sprite2.setmCurrentState(State.Standing);
sprite2.setLastKeyboard(keyCode);
return false;
}
}
if anyone knows where is my error or has a better code to show me I'll be happy, all I'm trying to do is to create a bitmap that moves around and can jump (but also jump while walking)
So I think what is happening in your code is that it's hitting the max height in the game loop and adding back to the y of the sprite. Second game loop run it is no longer above or near the max height distance therefore you stop going down and your start position becomes that position in the air. On a third loop through you hit spacebar again and your sprite starts the whole jumping processes over and the same thing happens on the next to loops through or however many it takes to trigger that if statement to get the sprite to start falling.
Good place to start is have a persistent boolean that determines whether or not the sprite is actually done climbing and jumping state should stay true while climbing and falling. See below.
boolean maxJumpAchieved = false;
if (mCurrentState == State.Jumping)
{
if (mStartingPosition.y - Position.y> 150)
{
maxJumpAchieved = true;
}
if (maxJumpAchieved) {
mDirection.y = MOVE_DOWN;
Position.y += mDirection.y * mSpeed;
}
if (Position.y > mStartingPosition.y)
{
maxJumpAchieved = false;
Position.y = mStartingPosition.y;
mCurrentState = State.Walking;
}
}
I think this should get you in the right direction but if you have issues let me know and I can edit my answer.
Another thing to note is don't set the mCurrentState to State.Walking until you know for sure you're on the ground otherwise you could double jump for days.
Related
So i was trying to make a simple mobile game for a school project. I setted up a simple SurfaceView thing and builded it on my phone with Android 12 (Api 32), but it doesn't draw anything. It enters the draw function of the view, but i can't see an output. It only works on a old friend's tablet with Android 4.4.2.
MySurfaceView.java
package com.example.lyceumgame;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
Bitmap image;
Paint paint;
float iX, iY, tX = 0, tY = 0;
float dx = 0, dy = 0;
Resources res;
MyThread myThread;
float ws, hs;
float iw, ih;
boolean isFirstDraw = true;
public MySurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
res = getResources();
iX = 100;
iY = 100;
paint = new Paint();
paint.setColor(Color.YELLOW);
paint.setStrokeWidth(5);
setAlpha(0);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
myThread = new MyThread(surfaceHolder, this);
myThread.setRunning(true);
myThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
boolean retry = true;
myThread.setRunning(false);
while (retry) {
try {
myThread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
setAlpha(0);
if (isFirstDraw){
ws = canvas.getWidth();
hs = canvas.getHeight();
isFirstDraw = false;
}
canvas.drawRGB(0,255,0);
canvas.drawLine(iX, iY, tX, tY, paint);
if(tX != 0)
delta();
iX += dx;
iY += dy;
checkScreen();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
tX = event.getX();
tY = event.getY();
delta();
return true;
}
void delta(){
double ro = Math.sqrt(Math.pow(tX-iX, 2)+Math.pow(tY-iY, 2));
double k = 10;
dx = (float) (k * (tX - iX)/ro);
dy = (float) (k * (tY - iY)/ro);
}
private void checkScreen(){
if(iY + ih >= hs && iY <= 0)
dy = -dy;
if(iX + iw >= ws && iX <= 0)
dx = -dx;
}
}
MyThread.java
package com.example.lyceumgame;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MyThread extends Thread {
boolean isRunning = false;
SurfaceHolder surfaceHolder;
MySurfaceView mySurfaceView;
long prevTime, nowTime;
int FPS=60;
int c=1000;
int koeff=c/FPS;
public MyThread(SurfaceHolder holder, MySurfaceView surfaceView) {
surfaceHolder = holder;
mySurfaceView = surfaceView;
prevTime = System.currentTimeMillis();
}
#Override
public void run() {
Canvas canvas;
while (isRunning){
if(!surfaceHolder.getSurface().isValid())
continue;
canvas = null;
nowTime = System.currentTimeMillis();
long ellapsedTime = nowTime - prevTime;
if(ellapsedTime > koeff){
prevTime = nowTime;
canvas = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder){
mySurfaceView.draw(canvas);
}
if (canvas != null){
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
void setRunning(boolean f){
isRunning = f;
}
}
MainActivity.java
package com.example.lyceumgame;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MySurfaceView(this));
}
}
My SDK was in different location and code like this worked fine. I tried invalidating caches and moving SDK to previous location. It didn't work.
I am unable to run my program. The app gets crashed. I am trying to make the image move on the screen by touchEvent.
java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.swapnil.new1.model.conmponents.Speed.getxDirection()' on a null object reference
at com.example.swapnil.new1.GamePanel.update(GamePanel.java:89)
at com.example.swapnil.new1.MainThread.run(MainThread.java:32)
I have added the Speed class which I think is responsible for this exception. Suggest any updates.
Speed class has the getxDirection method which is causing the exception.
package com.example.swapnil.new1.model.conmponents;
public class Speed {
public static final int DIRECTION_RIGHT = 1;
public static final int DIRECTION_LEFT = -1;
public static final int DIRECTION_UP = -1;
public static final int DIRECTION_DOWN = 1;
private float xv = 1; // speed in x
private float yv = 1; // speed in y
private int xDirection = DIRECTION_RIGHT;
private int yDirection = DIRECTION_DOWN;
public Speed() {
this.xv = 1;
this.yv = 1;
}
public Speed(float xv, float yv) {
this.xv = xv;
this.yv = yv;
}
public float getXv() {
return xv;
}
public void setXv(float xv) {
this.xv = xv;
}
public float getYv() {
return yv;
}
public void setYv(float yv) {
this.yv = yv;
}
public int getxDirection() {
return xDirection;
}
public void setxDirection(int xDirection) {
this.xDirection = xDirection;
}
public int getyDirection() {
return yDirection;
}
public void setyDirection(int yDirection) {
this.yDirection = yDirection;
}
public void toggleXDirection() {
xDirection = xDirection * -1;
}
public void toggleYDirection() {
yDirection = yDirection * -1;
}
}
The MainThread class:
package com.example.swapnil.new1;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();
private boolean running;
private SurfaceHolder surfaceHolder;
private GamePanel gamePanel;
public MainThread(SurfaceHolder surfaceHolder , GamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void run() {
Canvas canvas;
Log.d(TAG , "Starting game loop");
while(running) {
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
this.gamePanel.render(canvas);
this.gamePanel.update();
}
} finally {
if(canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
The GamePanel class:
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.example.swapnil.new1.model.Droid;
import com.example.swapnil.new1.model.conmponents.Speed;
public class GamePanel extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = GamePanel.class.getSimpleName();
private MainThread thread;
private Droid droid;
public GamePanel(Context context) {
super(context);
getHolder().addCallback(this);
droid = new Droid(BitmapFactory.decodeResource(getResources(),R.drawable.droid_1),50,50);
thread = new MainThread(getHolder() , this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
}catch (InterruptedException e) {
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
droid.handleActionDown((int)event.getX(),(int)event.getY());
if (event.getY() > getHeight() - 50) {
thread.setRunning(false);
((Activity)getContext()).finish();
} else {
Log.d(TAG , "Coords : x = " + event.getX() + ",y = " + event.getY());
}
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (droid.isTouched()) {
droid.setX((int)event.getX());
droid.setY((int) event.getY());
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
if (droid.isTouched()) {
droid.setTouched(false);
}
}
return true;
}
// changed protected to public
protected void render(Canvas canvas) {
canvas.drawColor(Color.BLACK);
droid.draw(canvas);
}
public void update() {
// collision with right
if (droid.getSpeed().getxDirection() == Speed.DIRECTION_RIGHT &&
droid.getX() + droid.getBitmap().getWidth()/2 >= getWidth()) {
droid.getSpeed().toggleXDirection();
}
//collision with left
if (droid.getSpeed().getxDirection() == Speed.DIRECTION_LEFT &&
droid.getX() - droid.getBitmap().getWidth()/2 <= 0) {
droid.getSpeed().toggleXDirection();
}
// collision with down
if (droid.getSpeed().getyDirection() == Speed.DIRECTION_DOWN &&
droid.getY() + droid.getBitmap().getHeight()/2 >= getHeight()) {
droid.getSpeed().toggleYDirection();
}
//collision with up
if (droid.getSpeed().getyDirection() == Speed.DIRECTION_UP &&
droid.getY() - droid.getBitmap().getHeight()/2 <= 0) {
droid.getSpeed().toggleYDirection();
}
droid.update();
}
}
Speed field in your Droid object is not set. In your GamePanel.update() method you are invoking getxDirection on this field and that cause NullPointerException.
OK, So Im drawing a bitmap beneath everything else for my background. Whenever the player moves it moves the enemy array 1 px and its supposed to do the same for the background. But whenever I move the background goes way faster and farther than everything else in the game. Can anyone tell me whats causing this? Heres the code. The code that moves everything is at the bottom in the set direction method.
package com.gametest;
import java.util.concurrent.CopyOnWriteArrayList;
import android.app.Activity;
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.Rect;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
public class GameSurfaceView extends Activity implements OnTouchListener {
double ran;
int touchX, touchY, screenWidth, screenHeight, objX, objY;
static int bgx, bgy, bgW, bgH, enemyCount, score, playerHealth;
static boolean canUpdate;
static MyView v;
static Bitmap orb, orb2, explosion, bg;
static CopyOnWriteArrayList<Sprite> copy = new CopyOnWriteArrayList<Sprite>();
static String hpString;
static Player player;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
v = new MyView(this);
v.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent me) {
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_MOVE:
return true;
case MotionEvent.ACTION_UP:
touchX = (int) me.getX();
touchY = (int) me.getY();
for (Sprite sprite : copy) {
sprite.checkTouch(touchX, touchY);
return true;
}
}
return true;
}
});
canUpdate = true;
screenWidth = v.getWidth();
screenHeight = v.getHeight();
playerHealth = 250;
hpString = "Health " + playerHealth;
ran = 0;
score = 0;
orb = BitmapFactory.decodeResource(getResources(), R.drawable.blue_orb);
orb2 = BitmapFactory.decodeResource(getResources(), R.drawable.red_orb);
bg = BitmapFactory.decodeResource(getResources(), R.drawable.bg1);
bgx = bg.getHeight()/2;
bgy = bg.getHeight()/2;
bgH = bg.getHeight();
bgW = bg.getWidth();
explosion = BitmapFactory.decodeResource(getResources(), R.drawable.explosion);
player = new Player(v, orb2, explosion, screenWidth, screenHeight);
createEnemies();
setContentView(v);
}
private void createEnemies() {
if (enemyCount < 5) {
screenWidth = v.getWidth();
screenHeight = v.getHeight();
copy.add(new Sprite(v, orb, explosion, screenWidth, screenHeight, copy.size()));
enemyCount++;
}
}
public static void checkECount(int id) {
canUpdate = false;
copy.remove(id);
enemyCount--;
CopyOnWriteArrayList<Sprite> c = new CopyOnWriteArrayList<Sprite>();
int index = 0;
for (Sprite s : copy) {
s.ID = index;
c.add(s);
index++;
}
score = score + 10;
copy = c;
canUpdate = true;
}
#Override
protected void onPause() {
super.onPause();
v.pause();
}
#Override
protected void onResume() {
super.onResume();
v.resume();
}
public class MyView extends SurfaceView implements Runnable {
Thread t = null;
SurfaceHolder holder;
boolean isItOk = false;
public MyView(Context context) {
super(context);
holder = getHolder();
}
#Override
public void run() {
while (isItOk == true) {
if (!holder.getSurface().isValid()) {
continue;
}
Canvas c = holder.lockCanvas();
if (canUpdate) {
canvas_draw(c);
}
holder.unlockCanvasAndPost(c);
try {
t.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
protected void canvas_draw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
Rect bgRec = new Rect(bgx, bgy, bgx+bgW, bgy+bgH);
canvas.drawBitmap(bg, null, bgRec, null);
ran = Math.random() * 5;
if (ran > 4.5) {
createEnemies();
}
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(15);
canvas.drawText(hpString, 10, 25, paint);
for (Sprite sprite : copy) {
sprite.sprite_draw(canvas);
}
Player.sprite_draw(canvas, copy);
}
public void pause() {
isItOk = false;
while (true) {
try {
t.join();
} catch (InterruptedException e) {
}
break;
}
t = null;
}
public void resume() {
isItOk = true;
t = new Thread(this);
t.start();
}
}
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
return false;
}
public static void damagePlayer() {
hpString = "Health " + playerHealth;
playerHealth = playerHealth - 5;
if (playerHealth < 0) {
hpString = "game over";
}
}
public static void setDirection(int i, int j) {
if (i == 0 && j == -1) {
for (Sprite s : copy) {
s.y++;
bgy++;
}
}
if (i == 0 && j == 1) {
for (Sprite s : copy) {
s.y--;
bgy--;
}
}
if (i == -1 && j == 0) {
for (Sprite s : copy) {
s.x++;
bgx++;
}
}
if (i == 1 && j == 0) {
for (Sprite s : copy) {
s.x--;
bgx--;
}
}
}
}
You are changing bgx based on the number of sprites you have in your copy Iterable. in your setDirection method, please move the bgy, bgx outside of the enhanced for loops, like in:
if (i == 0 && j == -1) {
for (Sprite s : copy) {
s.y++;
}
bgy++;
}
I have been researching and struggling with my code to get a textview to update the score when a "ghost" is touched.
This is my first Android application and so far as i can tell(i added Log.w() to the ontouch but a log is never posted as well as the score not being incremented or even appearing) the onTouch(View v, MotionEvent event) is never called. Below is my code.
package com.cs461.Ian;
//TODO:Add accelerometer support
//TODO:Add Clickable ghosts
//TODO:Add camera background
/*Completed:(As of 2:30am 4/16)
* Activity launches
* Ghost appears on screen
* Ghost will randomly move around the screen
*/
import java.util.Random;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.widget.TextView;
public class CameraActivity extends Activity{
Bitmap g;
Ghost a;
Ghost still;
SurfaceHolder mSurfaceHolder;
boolean firsttime=true;
int draw_x,draw_y,xSpeed,ySpeed,score=0;
TextView t;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
a = new Ghost(getApplicationContext());
still = new Ghost(getApplicationContext());
//requestWindowFeature(Window.FEATURE_NO_TITLE);
a.Initalize(BitmapFactory.decodeResource(getResources(), R.drawable.ghost), 20, 20);
still.Initalize(BitmapFactory.decodeResource(getResources(), R.drawable.ghost), 120, 120);
t = (TextView) findViewById(R.id.t);
t.setText("TEST SCORE TO SEE IF TEXTVIEW SHOWS UP");
a.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
score++;
t.setText("Score: "+score);
}
return true;
}
});
still.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
score++;
t.setText("Score: "+score);
Log.w("CLICKED","Clicked on ghost "+score+" times");
}
return true;
}
});
setContentView(new Panel(this));
}
class Panel extends View {
public Panel(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
//g.Initalise(BitmapFactory.decodeFile("/res/drawable-hdpi/ghost.png"), 200, 150, 5, 5);;
update(canvas);
invalidate();
}
/*Places ghost on screen and bounces it around in the screen. My phone is apparently only API level 4(the most up to date is 15) so i didn't code it
*for the accelerometer yet.
*/
public void update(Canvas canvas) {
Random rand = new Random();
if(firsttime){
draw_x = Math.round(System.currentTimeMillis() % (this.getWidth()*2)) ;
draw_y = Math.round(System.currentTimeMillis() % (this.getHeight()*2)) ;
xSpeed = rand.nextInt(10);
ySpeed = rand.nextInt(10);
firsttime=false;
}
draw_x+=xSpeed;
draw_y+=ySpeed;
draw_x = Math.round(System.currentTimeMillis() % (this.getWidth()*2)) ;
draw_y = Math.round(System.currentTimeMillis() % (this.getHeight()*2)) ;
if (draw_x>this.getWidth()){
draw_x = (this.getWidth()*2)-draw_x;
xSpeed = rand.nextInt(10);
if(xSpeed >=5)
xSpeed=-xSpeed;
}
if (draw_y>this.getHeight()){
draw_y = (this.getHeight()*2)-draw_y;
ySpeed = rand.nextInt(10);
if(ySpeed >=5)
ySpeed=-ySpeed;
}
g = BitmapFactory.decodeResource(getResources(), R.drawable.ghost);
canvas.drawBitmap(g, draw_x, draw_y, null);
still.draw(canvas);
a.update(canvas);
}
}
}
Forgot to add class Ghost:
package com.cs461.Ian;
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class Ghost extends View implements View.OnTouchListener{
public Ghost(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
private Bitmap mAnimation;
private int mXPos;
private int mYPos;
private Rect mSRectangle;
private int mSpriteHeight;
private int mSpriteWidth;
View v;
Rect dest;
int score = 0;
/*public Ghost() {
mSRectangle = new Rect(0,0,0,0);
mXPos = 80;
mYPos = 200;
}*/
public void Initalize(Bitmap theBitmap, int Height, int Width) {
mSRectangle = new Rect(0,0,0,0);
mXPos = 80;
mYPos = 200;
mAnimation = theBitmap;
mSpriteHeight = Height;
mSpriteWidth = Width;
mSRectangle.top = 0;
mSRectangle.bottom = mSpriteHeight;
mSRectangle.left = 0;
mSRectangle.right = mSpriteWidth;
dest = new Rect(mXPos, mYPos, mXPos + mSpriteWidth,
mYPos + mSpriteHeight);
}
public void draw(Canvas canvas) {
canvas.drawBitmap(mAnimation, mXPos, mYPos, null);
}
public void update(Canvas canvas) {
new Random();
mXPos = Math.round(System.currentTimeMillis() % (canvas.getWidth()*2)) ;
mYPos = Math.round(System.currentTimeMillis() % (canvas.getHeight()*2)) ;
if (mXPos>canvas.getWidth())
mXPos = (canvas.getWidth()*2)-mXPos;
if (mYPos>canvas.getHeight())
mYPos = (canvas.getHeight()*2)-mYPos;
draw(canvas);
}
public Rect getRect() {
return mSRectangle;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
score++;
//CameraActivity.t.setText("Score: "+CameraActivity.score);
Log.w("CLICKED","Clicked on ghost "+score+" times");
return true; //doesn't work if returns false either
}
}
Override dispatchTouchEvent(MotionEvent event) in your Activity to handle all the touch events that may occur. Return false to pass down the MotionEvent to the next view\layout in the hierachy if they they handle events.
What is the best way drawing a hero and moving it? I just need the best code for doing that. Before writing this i found a way, but when i made the surface holder transparent, i realised that the code is drawing new bitmap in the front of the old one every milisecond. That way looks kind of laggy to me, but maymie i'm not right. Please help me. Actualy i'm kind of confused...
Anyway, here's the code that i think is laggy:
MainThread.java
/**
*
*/
package com.workspace.pockethero;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
/**
* #author impaler
*
* The Main thread which contains the game loop. The thread must have access to
* the surface view and holder to trigger events every game tick.
*/
public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();
// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private MainGamePanel gamePanel;
// flag to hold game state
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run() {
Canvas canvas;
canvas = this.surfaceHolder.lockCanvas();
Log.d(TAG, "Starting game loop");
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
synchronized (surfaceHolder) {
// update game state
this.gamePanel.update();
// render state to the screen
// draws the canvas on the panel
this.gamePanel.render(canvas);
}
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
}
MainGamePanel.java
/**
*
*/
package com.workspace.pockethero;
import com.workspace.pockethero.model.Droid;
import com.workspace.pockethero.buttons.*;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
/**
* #author impaler
* This is the main surface that handles the ontouch events and draws
* the image to the screen.
*/
public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = MainGamePanel.class.getSimpleName();
private MainThread thread;
public Droid droid;
public Butt butt;
public Butt1 butt1;
public Butt2 butt2;
public Butt3 butt3;
public Buttz buttz;
public Buttz1 buttz1;
public Buttz2 buttz2;
public Buttz3 buttz3;
public Buttx buttx;
public Build build;
public int decentreX;
public int decentreY;
public int debottomA;
public boolean moved;
public boolean moved1;
public boolean moved2;
public boolean moved3;
public boolean moved4;
public boolean moved5;
public boolean moved6;
public boolean moved7;
private Drawable myImage;
public boolean mapPainted;
public MainGamePanel(Context context) {
super(context);
// adding the callback (this) to the surface holder to intercept events
getHolder().addCallback(this);
// create droid and load bitmap
decentreX = PocketHero.centreX;
decentreY = PocketHero.centreY;
debottomA = PocketHero.bottomA;
droid = new Droid(BitmapFactory.decodeResource(getResources(), R.drawable.herod), decentreX, decentreY);
butt = new Butt(BitmapFactory.decodeResource(getResources(), R.drawable.button), 110, debottomA - 70);
butt1 = new Butt1(BitmapFactory.decodeResource(getResources(), R.drawable.button1), 70, debottomA - 110);
butt2 = new Butt2(BitmapFactory.decodeResource(getResources(), R.drawable.button2), 30, debottomA - 70);
butt3 = new Butt3(BitmapFactory.decodeResource(getResources(), R.drawable.button3), 70, debottomA - 30);
buttz = new Buttz(BitmapFactory.decodeResource(getResources(), R.drawable.zbutton), 110, debottomA - 110);
buttz1 = new Buttz1(BitmapFactory.decodeResource(getResources(), R.drawable.zbutton1), 30, debottomA - 110);
buttz2 = new Buttz2(BitmapFactory.decodeResource(getResources(), R.drawable.zbutton2), 30, debottomA - 30);
buttz3 = new Buttz3(BitmapFactory.decodeResource(getResources(), R.drawable.zbutton3), 110, debottomA - 30);
buttx = new Buttx(BitmapFactory.decodeResource(getResources(), R.drawable.xbutton), 70, debottomA - 70);
build = new Build(BitmapFactory.decodeResource(getResources(), R.drawable.building), 500, 200);
// create the game loop thread
//300 indicates start position of bitmapfield on screen
thread = new MainThread(getHolder(), this);
// make the GamePanel focusable so it can handle events
setFocusable(true);
this.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View V, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// delegating event handling to the droid
handleActionDown((int)event.getX(), (int)event.getY());
} if (event.getAction() == MotionEvent.ACTION_MOVE) {
handleActionDown((int)event.getX(), (int)event.getY());
// the gestures
} if (event.getAction() == MotionEvent.ACTION_UP) {
// touch was released
if (droid.touched) {
droid.setTouched(false);
}
if (droid.touched1) {
droid.setTouched1(false);
}
if (droid.touched2) {
droid.setTouched2(false);
}
if (droid.touched3) {
droid.setTouched3(false);
}
}
return true;
}
});
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
// at this point the surface is created and
// we can safely start the game loop
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Surface is being destroyed");
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
Log.d(TAG, "Thread was shut down cleanly");
}
public void render(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
droid.draw(canvas);
butt.draw(canvas);
butt1.draw(canvas);
butt2.draw(canvas);
butt3.draw(canvas);
buttz.draw(canvas);
buttz1.draw(canvas);
buttz2.draw(canvas);
buttz3.draw(canvas);
buttx.draw(canvas);
}
/**
* This is the game update method. It iterates through all the objects
* and calls their update method if they have one or calls specific
* engine's update method.
*/
public void update() {
droid.update();
}
public void handleActionDown(int eventX, int eventY) {
if (eventX >= (butt.x - butt.bitmap.getWidth() / 2) && (eventX <= (butt.x + butt.bitmap.getWidth()/2))) {
if (eventY >= (buttz.y - buttz.bitmap.getHeight() / 2) && (eventY <= (buttz3.y + buttz3.bitmap.getHeight() / 2))) {
// droid touched
droid.setTouched(true);
} else {
droid.setTouched(false);
}
} else {
droid.setTouched(false);
}
if (eventX >= (buttz1.x - buttz1.bitmap.getWidth() / 2) && (eventX <= (buttz.x + buttz.bitmap.getWidth()/2))) {
if (eventY >= (butt1.y - butt1.bitmap.getHeight() / 2) && (eventY <= (butt1.y + butt1.bitmap.getHeight() / 2))) {
// droid touched
droid.setTouched1(true);
} else {
droid.setTouched1(false);
}
}else {
droid.setTouched1(false);
}
if (eventX >= (butt2.x - butt2.bitmap.getWidth() / 2) && (eventX <= (butt2.x + butt2.bitmap.getWidth()/2))) {
if (eventY >= (buttz1.y - buttz1.bitmap.getHeight() / 2) && (eventY <= (buttz2.y + buttz2.bitmap.getHeight() / 2))) {
// droid touched
droid.setTouched2(true);
} else {
droid.setTouched2(false);
}
}else {
droid.setTouched2(false);
}
if (eventX >= (buttz2.x - buttz2.bitmap.getWidth() / 2) && (eventX <= (buttz3.x + buttz3.bitmap.getWidth()/2))) {
if (eventY >= (butt3.y - butt3.bitmap.getHeight() / 2) && (eventY <= (butt3.y + butt3.bitmap.getHeight() / 2))) {
// droid touched
droid.setTouched3(true);
} else {
droid.setTouched3(false);
}
}else {
droid.setTouched3(false);
}
if (droid.touched & !droid.touched1 & !droid.touched3) {
if (!moved) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heror);
moved = true;
}
}else {
moved = false;
}if (droid.touched1 & !droid.touched & !droid.touched2){
if (!moved1) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herou);
moved1 = true;
}
}else {
moved1 = false;
} if (droid.touched2 & !droid.touched1 & !droid.touched3){
if (!moved2) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herol);
moved2 = true;
}
}else {
moved2 = false;
} if (droid.touched3 & !droid.touched2 & !droid.touched){
if (!moved7) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herod);
moved7 = true;
}
}else {
moved7 = false;
} if (droid.touched & droid.touched1){
if (!moved3) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herour);
moved3 = true;
}
}else {
moved3 = false;
} if (droid.touched1 & droid.touched2){
if (!moved4) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heroul);
moved4 = true;
}
}else {
moved4 = false;
} if (droid.touched2 & droid.touched3){
if (!moved5) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herodl);
moved5 = true;
}
}else {
moved5 = false;
} if (droid.touched3 & droid.touched){
if (!moved6) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herodr);
moved6 = true;
}
}else {
moved6 = false;
}
}
}
and the Droid.java
/**
*
*/
package com.workspace.pockethero.model;
import android.graphics.Bitmap;
import android.graphics.Canvas;
/**
* This is a test droid that is dragged, dropped, moved, smashed against
* the wall and done other terrible things with.
* Wait till it gets a weapon!
*
* #author impaler
*
*/
public class Droid {
public Bitmap bitmap; // the actual bitmap
public int x; // the X coordinate
public int y; // the Y coordinate
public boolean touched; // if droid is touched/picked up
public boolean touched1; // if droid is touched/picked up
public boolean touched2; // if droid is touched/picked up
public boolean touched3; // if droid is touched/picked up
public Droid(Bitmap bitmap, int x, int y) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void draw(Canvas canvas) {
canvas.drawBitmap(bitmap, x - (bitmap.getWidth() / 2), y - (bitmap.getHeight() / 2), null);
}
/**
* Method which updates the droid's internal state every tick
*/
public void setTouched(boolean touched) {
this.touched = touched;
}
public boolean isTouched() {
return touched;
}
public void setTouched1(boolean touched) {
this.touched1 = touched;
}
public boolean isTouched1() {
return touched1;
}
public void setTouched2(boolean touched) {
this.touched2 = touched;
}
public boolean isTouched2() {
return touched2;
}
public void setTouched3(boolean touched) {
this.touched3 = touched;
}
public boolean isTouched3() {
return touched3;
}
public void update() {
if (touched & !touched1 & !touched3) {
x += 1;
}else if (touched1 & !touched & !touched2){
y -= 1;
}else if (touched2 & !touched1 & !touched3){
x -= 1;
}else if (touched3 & !touched2 & !touched){
y += 1;
}else if (touched & touched1){
x += 1;
y -= 1;
}else if (touched1 & touched2){
x -= 1;
y -= 1;
}else if (touched2 & touched3){
x -= 1;
y += 1;
}else if (touched3 & touched){
x += 1;
y += 1;
}
}
/**
* Handles the {#link MotionEvent.ACTION_DOWN} event. If the event happens on the
* bitmap surface then the touched state is set to <code>true</code> otherwise to <code>false</code>
* #param eventX - the event's X coordinate
* #param eventY - the event's Y coordinate
*/
}
there are also other classes created for each button, but i didnt pasted them here, because the are practicly the same as droid.java
Re-drawing the whole frame each loop is the correct way to draw/move sprites and perform anything with canvas.
The buffer is cleared each frame and you need to re-draw the background and all objects at their specified position.
In your code render() and update() will not be called more frequently than approximately every 16milliseconds~ (60 frames per second), so all you have to think about is drawing the onscreen scene.
I'm not sure what you mean by 'laggy', maybe you have a performance issue related to the size of your Bitmaps or phone performance, but I hope this is close to what you were looking for.