I'm current creating a game and i've made 3 main classes - GameView (which extends surfaceview), GameViewThread (which is a thread used for surfaceview) and a MainActivity.
I want to enter a background image in SurfaceView, but have not been able to figure out how to do so.
Using setBackground() in the onDraw method of GameView doesn't work as well.
I would greatly appreciate any help you guys can provide me with.
Here is my GameView class:
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private Bitmap bmp1;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private Sprite sprite;
private float sensorX = 0;
private Platform platform[] = new Platform[7];
private Bonus GravUp[] = new Bonus[3];
private Bonus GravDown[] = new Bonus[3];
private Bitmap bmp2;
private Bitmap bmp3;
private boolean collision;
private int a;
private int b;
private int c1;
private double c2;
int agility = 50;
private Bitmap bmp4;
public double getsensorX() {
return sensorX;
}
public double setsensorX(float s) {
return sensorX = s;
}
synchronized public int getSpriteY() {
return sprite.y;
}
synchronized public int getSpriteX() {
return sprite.x;
}
synchronized public int getSpriteHeight() {
return sprite.height;
}
synchronized public int getSpriteWidth() {
return sprite.width;
}
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(this);
bmp1 = BitmapFactory.decodeResource(getResources(), R.drawable.russel);
sprite = new Sprite(this);
sprite.getBMP(bmp1);
bmp2 = BitmapFactory.decodeResource(getResources(), R.drawable.brick);
bmp3 = BitmapFactory.decodeResource(getResources(), R.drawable.gravup);
bmp4 = BitmapFactory.decodeResource(getResources(), R.drawable.gravdown);
for (int i = 0; i < GravUp.length; i++) {
GravUp[i] = new Bonus(this, bmp3);
}
for (int i = 0; i < GravDown.length; i++) {
GravDown[i] = new Bonus(this, bmp4);
}
for (int i = 0; i < platform.length; i++) {
Random r = new Random();
platform[i] = new Platform(this, bmp2, 850 + 200 * i,
400 - r.nextInt(250));
}
}
#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) {
canvas.drawColor(Color.YELLOW);
sprite.Draw(canvas);
for (int i = 0; i < platform.length; i++) {
platform[i].Draw(canvas);
}
for (int i = 0; i < GravUp.length; i++) {
GravUp[i].Draw(canvas);
}
for (int i = 0; i < GravDown.length; i++) {
GravDown[i].Draw(canvas);
}
}
My MainActivity Class:
public class MainActivity extends Activity {
GameView gameView;
FrameLayout game;
RelativeLayout GameButtons;
Button butOne;
Button butTwo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameView = new GameView(this);
game = new FrameLayout(this);
GameButtons = new RelativeLayout(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT);
GameButtons.setLayoutParams(params);
game.addView(gameView);
game.addView(GameButtons);
setContentView(game);
}
}
How can I use an image I have saved in res/drawable-hdpi folder as the background to my game?
Should I use the command in GameView or MainActivity?
Do let me know if you need more information in order to help me out!
Thank you
Related
I am a newbie in android and started with livewallpaper development using Wallpaper Engine. My problem is the run() method inside Runnable is not called dont know why.... Am I missing something?
Here is my code:
public class Hearts extends WallpaperService {
public static boolean LANDSCAPE;
public static Paint backgroundPaint;
public static Point backgroundSize;
public static Point globalCanvasSize;
public static boolean landscapeMode = false;
public static int maxScreenSize;
Bitmap background;
private final Handler mHandler = new Handler();
public void onCreate() {
super.onCreate();
}
public WallpaperService.Engine onCreateEngine() {
return new HeartsEngine();
}
public void onDestroy() {
super.onDestroy();
}
class HeartsEngine extends Engine {
private final int amountOfFlakes = 40;
private final Paint backgroundPaint = new Paint();
private Canvas c;
public Flake[] flakeArray = new Flake[40];
final SurfaceHolder holder = getSurfaceHolder();
private final Runnable mDrawCube = new Runnable() {
#Override
public void run() {
Log.d("tag", "Inside Run Called");
drawFrame();
}
};
float mXOffset;
float mYOffset;
private float oldScreen;
Random random = new Random();
Resources res = Hearts.this.getResources();
HeartsEngine() {
super();
Log.d("tag", "Constructyor");
}
void drawFrame() {
Log.d("tag", "drawFrame");
this.oldScreen -= this.mXOffset;
Flake.scrollSpeed = 48.0F * this.oldScreen;
this.oldScreen = this.mXOffset;
this.c = null;
this.c = this.holder.lockCanvas();
try {
if (this.c != null)
this.c.drawBitmap(Hearts.this.background, 0.0F, 0.0F, null);
for (int i = 0;; i++) {
if (i >= 40) {
this.holder.unlockCanvasAndPost(this.c);
Hearts.this.mHandler.postDelayed(this.mDrawCube, 16L);
}
this.flakeArray[i].updateFlake(this.random, this.res,
this.c);
}
} catch (IllegalArgumentException localIllegalArgumentException) {
// break label94;
localIllegalArgumentException.printStackTrace();
return;
}
}
You call drawFrame() only inside the mDrawCube Runnable. So there is no a first time call for the drawFrame() method
I'm new to programming in android and I can't understand why the OnDraw() method in my renderer doesn't get called as invalidate() is called. The final set background resource does get called however. There are 2 classes, Game.java and Renderer.java. It seems that the invalidate call does not have time to get processed during the loop in game.
Game.Java
public class Game extends Activity
{
Level currentLevel;
private static List<Entity> _renderList = new ArrayList<Entity>();
public void StartLevel(View view)
{
System.out.println("I HAVE STARTED THE LEVEL!");
// Hide the play button
Button playButton = (Button) findViewById(R.id.start_game);
playButton.setVisibility(View.GONE);
// Load the level
currentLevel = new Level1(this);
// Create the initial entities
// Add the entities to the screen
List<Bitmap> bitmapList;
bitmapList = new ArrayList<Bitmap>();
Bitmap enemy = BitmapFactory.decodeResource(getResources(), R.drawable.enemy);
bitmapList.add(enemy);
System.out.println("CREATING RENDERER!");
Renderer renderer = new Renderer(this, _renderList, bitmapList);
renderer.setBackgroundResource(R.drawable.beachbackground);
setContentView(renderer);
System.out.println("STARTING TRAVEL!");
while (currentLevel.GetDistTravelled() < currentLevel.GetDist())
{
Retrieve();
currentLevel.AddDistance(1);
System.out.println("DISTANCE +1!");
renderer.RenderFrame(_renderList);
System.out.println("RENDER LEVEL FRAME!");
try
{
Thread.currentThread().sleep(50);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("SET BACKGROUND!");
renderer.setBackgroundResource(R.drawable.menubackground);
}
public List<Entity> GetRenderList()
{
return _renderList;
}
private void Retrieve()
{
// get the array
Entity[] enemies;
enemies = currentLevel.CheckSpawn();
if(enemies != null)
{
// parse the array into entities
int length = enemies.length;
System.out.println(length);
// remember to Get enemy strings
for(int i = 0; i < length; i++)
{
// add them to our array
_renderList.add(enemies[i]);
}
}
}
}
Renderer.java
class Renderer extends SurfaceView implements SurfaceHolder.Callback
{
PanelThread _thread;
List<Entity> _renderList = new ArrayList<Entity>();
List<Bitmap> _bitmapList = new ArrayList<Bitmap>();
public Renderer(Context context, List<Entity> renderList, List<Bitmap> bitmapList)
{
super(context);
getHolder().addCallback(this);
_bitmapList = bitmapList;
}
public void RenderFrame(List<Entity> renderList)
{
for (int i = 0; i < renderList.size(); i++)
{
_renderList.add(renderList.get(i));
}
invalidate();
}
#Override
public void onDraw(Canvas canvas)
{
Paint paint = null;
// Draw enemies
if(_renderList.size() != 0 && _renderList != null)
{
int size = _renderList.size();
for(int i = 0; i < size; i++)
{
canvas.drawBitmap(_bitmapList.get(_renderList.get(i).GetBitmapID()), _renderList.get(i).GetX(), _renderList.get(i).GetY(), paint);
}
}
}
// position the train on the screen in the appropriate place
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
setWillNotDraw(false); //Allows us to use invalidate() to call onDraw()
_thread = new PanelThread(getHolder(), this); //Start the thread that
_thread.setRunning(true); //will make calls to
_thread.start(); //onDraw()
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
try
{
_thread.setRunning(false); //Tells thread to stop
_thread.join(); //Removes thread from mem.
}
catch (InterruptedException e) {}
}
class PanelThread extends Thread
{
private SurfaceHolder _surfaceHolder;
private Renderer _renderer;
private boolean _run = false;
public PanelThread(SurfaceHolder surfaceHolder, Renderer renderer)
{
_surfaceHolder = surfaceHolder;
_renderer = renderer;
}
public void setRunning(boolean run)
{
_run = run;
}
#Override
public void run()
{
Canvas c;
while (_run)
{
c = null;
try
{
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder)
{
//Insert methods to modify positions of items in onDraw()
postInvalidate();
}
}
finally {
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
Any help on solving this problem would be very grateful. If anymore info is needed just ask.
Hi i have the same error like you. But i have found that. But i don't known clearly about that.
but you can try
add the attribute android:background to your layout.
I'm developing a simple game like BSD robots. This game contains a rather large board (over 40 cells) and it doesn't look nice even at 10 inch tablet. My decision was to scroll (move) surface view and not to scale each figure which size is like finger spot.
I've read tons articles about surface view but I cannot understand how to move it?
My activity code:
package ru.onyanov.robots;
public class MainActivity extends Activity {
public BoardView board;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
board = new BoardView(this);
setContentView(board);
}
}
Class Board:
package ru.onyanov.robots;
public class BoardView extends SurfaceView {
private GameThread mThread;
private boolean running = false;
public final int sizeX = 50;
public final int sizeY = 35;
public final int cellSize = 64;
private int robotCount = 4;
public ArrayList<Cell> cells = new ArrayList<Cell>();
private ArrayList<Robot> robots = new ArrayList<Robot>();
private Hero hero;
public Bitmap imageCell;
public Bitmap imageRobot;
public Bitmap imageHero;
public BoardView(Context context) {
super(context);
makeGraphic();
constructCells();
constructRobots();
hero = new Hero(this, 3, 2, imageHero);
mThread = new GameThread(this);
getHolder().addCallback(new SurfaceHolder.Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mThread.setRunning(false);
while (retry) {
try {
mThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
mThread.setRunning(true);
mThread.start();
}
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
private void makeGraphic() {
Bitmap cellImageSource = BitmapFactory.decodeResource(getResources(),
R.drawable.cell);
imageCell = Bitmap.createScaledBitmap(cellImageSource, cellSize,
cellSize, false);
imageRobot = BitmapFactory.decodeResource(getResources(),
R.drawable.robot);
imageHero = BitmapFactory.decodeResource(getResources(),
R.drawable.hero);
}
private void constructRobots() {
Robot robot;
Random rand = new Random();
for (int r = 0; r < robotCount; r++) {
int x = rand.nextInt(sizeX);
int y = rand.nextInt(sizeY);
robot = new Robot(this, x, y, imageRobot);
robots.add(robot);
}
return;
}
private void constructCells() {
Cell cell;
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++) {
cell = new Cell(this, x, y, imageCell);
cells.add(cell);
}
}
return;
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Cell cell;
for (int c = 0; c < cells.size(); c++) {
cell = cells.get(c);
cell.onDraw(canvas);
}
Robot robot;
for (int r = 0; r < robots.size(); r++) {
robot = robots.get(r);
robot.onDraw(canvas);
}
hero.onDraw(canvas);
}
public boolean onTouchEvent(MotionEvent e) {
int shotX = (int) e.getX();
int shotY = (int) e.getY();
if (e.getAction() == MotionEvent.ACTION_MOVE){
//TODO move board
showToast("move Board");
} else if (e.getAction() == MotionEvent.ACTION_UP) {
showToast("touchPoint: " + shotX + ", "+shotY);
hero.moveByDirection(shotX, shotY);
this.scrollTo(shotX, shotY);
}
return true;
}
public void showToast(String mes) {
Toast toast = Toast.makeText(getContext(), mes, Toast.LENGTH_LONG);
toast.show();
}
public class GameThread extends Thread {
private BoardView view;
public GameThread(BoardView view) {
this.view = view;
}
public void setRunning(boolean run) {
running = run;
}
public void run() {
while (running) {
Canvas canvas = null;
try {
canvas = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
onDraw(canvas);
}
canvas.scale(300, 300);
} catch (Exception e) {
} finally {
if (canvas != null) {
view.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
}
}
Some magic digits here are temporary. Now I just want to move BoardView;
The issue was to add x and y fields to SurfaceView, change them at onTouchEvent and draw all the elements in canvas with x- and y-offset. It's strange that I didn't recieved any answers...
I'm new in Android and I want to do some animations. I'm trying to make my sprite sheet move automatically. But there is a problem with screen rendering. It leaves a trail while it is moving.Click here to see the screen shot
This is my code:
public class SampleAnimationActivity extends Activity {
/** Called when the activity is first created. */
Screen screen;
MapAnimation mapAnimation;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
screen = new Screen(this);
setContentView(screen);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
}
public class Screen extends SurfaceView implements Callback{
private SurfaceHolder holder;
private MySurfaceViewThread mySurfaceViewThread;
private boolean isSurfaceCreated;
private Bitmap character, tiles;
public Screen(Context context) {
super(context);
initialize();
}
public void initialize(){
//Create a new SurfaceHolder and assign this class as its callback...
holder = getHolder();
holder.addCallback(this);
isSurfaceCreated = false;
character = BitmapFactory.decodeResource(getResources(),R.drawable.penguin_sprite);
tiles = BitmapFactory.decodeResource(getResources(), R.drawable.tile_sprites);
resume();
}
public void resume(){
//Create and start the graphics update thread.
if(mySurfaceViewThread == null){
mySurfaceViewThread = new MySurfaceViewThread();
if(isSurfaceCreated == true){
mySurfaceViewThread.start();
}
}
}
public void pause(){
//Kill the graphics update thread
if(mySurfaceViewThread != null){
mySurfaceViewThread.pause();
mySurfaceViewThread = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
isSurfaceCreated = true;
if(mySurfaceViewThread != null){
mySurfaceViewThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
isSurfaceCreated = false;
pause();
}
public class MySurfaceViewThread extends Thread{
private boolean isPaused;
private boolean characterLoaded, characterDrawn;
private SurfaceHolder surfaceHolder;
public MySurfaceViewThread(){
super();
isPaused = false;
characterLoaded = false;
surfaceHolder = holder;
characterDrawn = false;
}
public void run(){
//Repeat the drawing loop until the thread is stopped
while(!isPaused){
if(!surfaceHolder.getSurface().isValid()){
continue;
}
if(characterLoaded == false){
mapAnimation = new MapAnimation(screen, character);
characterLoaded = true;
}
Canvas canvas = surfaceHolder.lockCanvas();
mapAnimation.onDraw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
public void pause(){
}
public void onDraw(){
}
}
}
}
public class MapAnimation {
private Screen screen;
private Bitmap character;
private int width, height, xPosition, yPosition, xSpeed, ySpeed;
public MapAnimation(Screen screen, Bitmap character) {
this.screen = screen;
this.character = character;
this.width = character.getWidth();
this.height = character.getHeight();
xPosition = 0;
yPosition = 0;
xSpeed = 5;
ySpeed = 5;
}
public void updateCharacter(){
if(xPosition > screen.getWidth() - width - xSpeed){
xSpeed = 0;
ySpeed = 5;
}
if(yPosition > screen.getHeight() - height - ySpeed){
xSpeed = -5;
ySpeed = 0;
}
if(xPosition + xSpeed < 0){
xPosition=0;
xSpeed = 0;
ySpeed = -5;
}
if(yPosition+ySpeed < 0){
yPosition = 0;
xSpeed = 5;
ySpeed = 0;
}
xPosition += xSpeed;
yPosition += ySpeed;
}
public void onDraw(Canvas canvas){
updateCharacter();
Rect src = new Rect(0, 0,135,225);
Rect dst = new Rect(xPosition, yPosition, xPosition+width, yPosition+height);
canvas.drawBitmap(character, src, dst, null);
}
}
Your help will be deeply appreciated :)
I already solved my problem, I just need to add "drawColor(color.BLACk);" before calling mapAnimation.onDraw() method.
I'm puzzled with the problem "AnimationDrawable not change frames" for some time.I'm confirmed I've added all the frames I need into the AnimationDrawable object,and I've called start(),and the result I called isRunning() is true,but the AnimationDrawable can't change the frame.
I called the start() in MainActivity's handler,not in onCreate() or onResume(),although the the called of start() is in the onResume() state.
Thanks for your thinkings.
----^_^ banlalaotou.
Added code which has the problem.
public class MainActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ma = new Ma(this);
ablt = ma.ablt;
setContentView(ablt);
mt = new MinorThread(this);
new Thread(mt).start();
while(true){
if(mt.mHandler==null) continue;
else{
Message msg = new Message();
mt.mHandler.sendMessage(msg);
break;
}
}
}
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
ma.control();
Message msg1 = new Message();
mt.mHandler.sendMessage(msg1);
}
};
#Override
public boolean onKeyDown(int keyCode,KeyEvent event){
switch(keyCode){
case KeyEvent.KEYCODE_BACK:
System.exit(0);
}
return true;
}
private MinorThread mt = null;
private ImageView v1 = null;
private Ma ma = null;
private int x = 0;
private int y = 0;
private int width = 0;
private int height = 0;
private AbsoluteLayout ablt = null;
}
class MinorThread implements Runnable{
#Override
public void run() {
Looper.prepare();
mHandler = new Handler(){
#Override
public void handleMessage(Message msg){
Message msg2 = new Message();
mainActivity.handler.sendMessage(msg2);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Looper.loop();
}
public MinorThread(MainActivity mainAcitivy){
this.mainActivity = mainAcitivy;
}
private MainActivity mainActivity = null;
public Handler mHandler = null;
}
class Ma{
public Ma(MainActivity context){
ablt = new AbsoluteLayout(context);
TestView v = new TestView(context);
AbsoluteLayout.LayoutParams lp = new LayoutParams(480,320,0,0);
ablt.addView(v, lp);
Drawable d = null;
ad = new AnimationDrawable();
d = context.getResources().getDrawable(R.drawable.f1);
ad.addFrame(d, 100); d = context.getResources().getDrawable(R.drawable.f2);
ad.addFrame(d, 100); d = context.getResources().getDrawable(R.drawable.f3);
ad.addFrame(d, 100); d = context.getResources().getDrawable(R.drawable.f4);
ad.addFrame(d, 100); d = context.getResources().getDrawable(R.drawable.f5);
ad.addFrame(d, 100);
v1 = new ImageView(context);
v1.setImageDrawable(ad);
String tag = "test";
v1.setTag(tag);
ablt.addView(v1, new LayoutParams(100, 40, 20, 20));
}
public void control(){
v1 = (ImageView) ablt.findViewWithTag("test");
if(x<480&&y<320){
x+=10;
y+=5;
v1.layout(x, y, x+100, y+40);
AnimationDrawable ad = (AnimationDrawable)v1.getDrawable();
ad.start();
}
}
public AbsoluteLayout ablt = null;
private AnimationDrawable ad = null;
private ImageView v1 = null;
private int x = 0;
private int y = 0;
private int width = 0;
private int height = 0;
}
class TestView extends View{
public TestView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas){
paint.setColor(Color.WHITE);
canvas.drawRect(0,0,480,320, paint);
}
private Paint paint = new Paint();
}
I'sorry for not uploaded the frames,because my reputation is less than 10.
If you execute the code,you need to find some pictures to let the animation run.
thanks.
=============================
Now,I know how to let the result show,but I can't know the resaon.
The solution of the problem is that add a ImageView object into the layout object before show the all ImageView,and, "add a ImageView..." and "show the all ImageView" can't been processed in an function.The right method is like that "if(..){add a ImageView}else{show the all ImageView}".
Although,this method can resolve the problem I'd puzzeled,but why Android can't show the all ImageView's animations at first time?
Try to use start() in onWindowFocusChange(boolean focus) when focus is true.