I believe the problem I have is that gameThread won't work unless I have use GL10 gl in gameview.drawFrame(). I've tried creating a Object gl passing that in but still wont work. Also is it wrong to use game.onResume to update the game?
I've created an instance of the gameThread inside of Main.class and classed the
public class GameThread extends Thread {
Object gl;
private static int MAX_FRAME_SKIPS;
private static int FRAME_PERIOD;
private OpenGLActivity game;
private MyGLRenderer gameView;
private boolean gameRunning = true;
private boolean running = false;
Handler handler = new Handler();
public GameThread( int maxFPS, int maxFrameSkips) {
game = new OpenGLActivity();
gameView = new MyGLRenderer();
MAX_FRAME_SKIPS = maxFrameSkips;
FRAME_PERIOD = 1000 / maxFPS;
gl = new Object();
}
#Override
public void run() {
long beginTime;
long timeDiff;
int sleepTime;
int framesSkipped;
beginTime = System.currentTimeMillis();
framesSkipped = 0;
this.gameRunning = this.game.isRunning();
this.game.onResume(); // Update game
this.gameView.onDrawFrame((GL10) gl); // Render the game
timeDiff = System.currentTimeMillis() - beginTime; // Calculate cycle length
sleepTime = (int) (FRAME_PERIOD - timeDiff); // Calculate time available to sleep
// Checks if got time to sleep, either sleeps thread or catches up
if (sleepTime > 0) {
if (this.gameRunning && running) {
handler.postDelayed(this, sleepTime);
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
this.game.onResume(); // Update without rendering
sleepTime += FRAME_PERIOD; // Add frame period to check if in next frame
framesSkipped++;
if (this.gameRunning && running) {
this.run(); // No time to wait! RUN! CATCH UP!
}
}
}
}
public void setRunning(boolean running) {
this.running = running;
}
}
public class Main extends Activity{
GameThread gt = new GameThread(48, 100);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
public void PlayGame(View v) {
Intent intent = new Intent(Main.this, OpenGLActivity.class);
startActivity(intent);
gt.setRunning(true);
}
The fact that you don't have a GL10 object is only a symptom here. In fact, I don't think that's ever used on Android. It's part of the javax.microedition.khronos.opengles package, which I figure is some kind of standard Java OpenGL ES interface. I'm not sure if it's functional, but I certainly have never seen anybody use it.
The OpenGL interfaces that are normally used in Android are in the android.opengl package, and are named GLES10, GLES11, GLES20, GLES30, GLES31.
On those classes, all the methods are static. So you never really need an object instance to make OpenGL calls.
But, and this is your actual problem: To make OpenGL calls, you need to create an OpenGL context, and make it current. You will also need a rendering surface. There are two main options for this:
The (moderately) hard way by using the EGL14 interface (or EGL10 if you need to support API levels lower than 17).
You can go the more convenient and widely used route, and use a GLSurfaceView, which creates the context and rendering surface for you.
I recommend that you start with the official tutorial in the Android documentation. All of the above will become much clearer once you go through this: http://developer.android.com/training/graphics/opengl/index.html.
You should also be aware that OpenGL ES 1.x is mostly considered obsolete. ES 2.0 and higher versions are much more widely used these days.
Related
I am making space invaders game. This is main acitivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// Get a Display object to access screen details
Display display = getWindowManager().getDefaultDisplay();
// Load the resolution into a Point object
Point size = new Point();
display.getSize(size);
spaceInvadersEngine = new SpaceInvadersEngine(this, size.x, size.y);
setContentView(spaceInvadersEngine);
}
// This method executes when the player starts the game
#Override
protected void onResume() {
super.onResume();
// Tell the gameView resume method to execute
spaceInvadersEngine.resume();
}
// This method executes when the player quits the game
#Override
protected void onPause() {
super.onPause();
// Tell the gameView pause method to execute
spaceInvadersEngine.pause();
}
Class SpaceInvadersEngine has two main functions update() where all calculation is done and draw() where I draw all elements. After adding more elements game works but it is slow, so I decided to separate it in more threads.
This is my code in SpaceInvadersEngine
public void resume() {
playing = true;
gameThread = new Thread(runnable);
gameThread.start();
drawThread = new Thread(this);
drawThread.start();
}
In gameThread runnable I have
while(playing){update();}
and for drawThread in run() i have only draw();
While game load and prepare for new level (create new invader and upgrade objects) it takes up to 5 seconds and game freeze. How to remove that waiting time? When I try drawThread with runnabletoo, it does not draw anything.
Also, for some reason, when I do with two threads, my shipsometimes random blink as a big image in one frame, and then returns to normal, it was not blinking in single thread?
I would suggest you using Kotlin language with coroutines for asynchronous code. It's not hard to start using and it can really improve overall performance and code readability.
fun exampleMethod() {
// Starts a new coroutine on Dispatchers.Main as it's the scope's default
val job1 = scope.launch {
// New coroutine with CoroutineName = "coroutine" (default)
}
// Starts a new coroutine on Dispatchers.Default
val job2 = scope.launch(Dispatchers.Default + "BackgroundCoroutine") {
// New coroutine with CoroutineName = "BackgroundCoroutine" (overridden)
}
}
If you are open to change technology a bit, look at this and try coroutines. It's a fresh and great way how to deal with long-running tasks on Android. Also, you can find many articles and examples for them.
Improve app performance with Kotlin coroutines
I am currently having some trouble when running the follwing code. If I delete this part the problems disappear so this part of my whole code has to be the problem. It runs and draws what I want perfectly but after a few seconds (maxAddedRuntime is set via user (milliseconds)) the application freezes for a while (window is not responding Windows message) and starts over with drawing after waiting approximately the same time while the window is frozen. What do I do wrong?
I am using SWT and a canvas to draw. Thank you for your help
public void drawNetwork(Canvas canvas, GC gc, Network network, Shell shlNetworkVisualizer) {
startTime = System.currentTimeMillis();
endTime = startTime + maxAddedRuntime;
this.drawNetworkAlg1(canvas, gc, network);
int canvasHeight = canvas.getBounds().height;
int canvasWidth = canvas.getBounds().width;
while (System.currentTimeMillis()<endTime) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
gc.fillRectangle(0, 0, canvasWidth, canvasHeight); //ClearCanvas basically
for (Nodek: network.node) {
//drawSomeStuff
}
for (Edge k: network.edges) {
//alsoDrawSomeStuff
}
}
}
An SWT app must return to the main Display.readAndDispatch loop as quickly as possible. So you cannot use a loop with a Thread.sleep call - this will just lock up the UI until the loop ends.
Instead you can use Display.timerExec to run code after a delay. You would use this to run a single step (just one gc.fillRectange for example) and then call Display.timerExec again to schedule the next step.
public void timerExec(int milliseconds, Runnable runnable)
Note: The GC you receive from a paint event is only valid during the paint. The timerExec call should normally just call redraw on the canvas to cause a new paint event to be generated.
Here is a simple class that does basic timerExec calls and paints:
class Progress
{
private final Canvas canvas;
private final long endTime;
Progress(Canvas c)
{
canvas = c;
endTime = System.currentTimeMillis() + 1_000;
canvas.addListener(SWT.Paint, this::paint);
canvas.getDisplay().timerExec(100, this::timer);
}
private void paint(Event event)
{
GC gc = event.gc;
int canvasHeight = canvas.getBounds().height;
int canvasWidth = canvas.getBounds().width;
gc.fillRectangle(0, 0, canvasWidth, canvasHeight);
// TODO more painting
}
private void timer()
{
if (canvas.isDisposed()) { // Don't continue if control closed
return;
}
canvas.redraw();
if (System.currentTimeMillis() < endTime) {
canvas.getDisplay().timerExec(100, this::timer);
}
}
}
So I have a game that I'm trying to make and in the game loop, I call Thread.sleep(). Else where, I have code that maintains the aspect ratio of the window when resizing. This works great, except that I get weird flickering when I'm resizing. I've narrowed the problem down to Thread.sleep(), when I take this line out, my program works just as expected, but this causes the CPU to spike so high that on my Macbook, the Activity Monitor app says my game is using 170+%! Now this is problematic and exactly why I put the sleep line in there anyway. I've heard that sleeping on the event dispatch thread will cause this effect, but I am running this loop in a new thread, so I thought I was good. Do you guys know what could be going on? Here's part of the source code (you really need to look at the run() method):
package jeffrey_ryan.game2d;
public class GameLoop implements Runnable {
private boolean running = false;
private boolean paused = false;
private float gameHertz = 30.0f;
private long timeBetweenUpdates = (long) (1_000_000_000 / gameHertz);
private int maxUpdates = 5;
private LoopListener loopListener;
public void run() {
long lastUpdateTime = System.nanoTime();
running = true;
while (running) {
long now = System.nanoTime();
if (!paused) {
int updates = 0;
while (now - lastUpdateTime >= timeBetweenUpdates && updates < maxUpdates) {
if (loopListener != null) {
loopListener.update((double) timeBetweenUpdates / 1_000_000_000);
}
lastUpdateTime += timeBetweenUpdates;
updates++;
}
if (loopListener != null) {
float interpolation = Math.min(1.0f, (float) (now - lastUpdateTime) / timeBetweenUpdates);
loopListener.render(interpolation);
}
long timeRemaining = (timeBetweenUpdates - (now - lastUpdateTime)) / 1_000_000;
try {
Thread.sleep(Math.max(timeRemaining - 5, 0)); // HERE'S THE OFFENDING LINE ******************
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
else {
try {
Thread.sleep(25);
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}
public void start() {
running = true;
}
public void stop() {
running = false;
}
public void pause() {
paused = true;
}
public void play() {
paused = false;
}
public float getSpeed() {
return gameHertz;
}
public void setSpeed(float hertz) {
gameHertz = hertz;
timeBetweenUpdates = (long) (1_000_000_000 / gameHertz);
}
public int getMaxUpdates() {
return maxUpdates;
}
public void setMaxUpdates(int updates) {
maxUpdates = updates;
}
public void setLoopListener(LoopListener listener) {
loopListener = listener;
}
}
In my subclass of JPanel, here's the code that runs this loop (Where the loop variable is an instance of the above class):
#Override
public void addNotify() {
super.addNotify();
addKeyListener(this);
addMouseListener(this);
Thread thread = new Thread(loop, "GameLoop");
thread.start();
}
If you guys could help me I would love it, I'm really stumped. Thanks!
You should use SwingWorker instead of a Thread to manipulate Swing components asynchronously. When I discovered this guy my life changed =). The SwingWorker gives you a method "process" which you can use to make actions gradually, and a "done" method to finish your processing, both of these methods are safe to handle the event dispatch thread. The background process you should make on "doInBackground".
Calling 'Thread.sleep(n)' causes the whole thread to become unresponsive, if this thread is tied to your JFrame thread then that thread will also become unresponsive and cause the whole frame and component to freeze and stop responding -- probably the reason for the flickering. So make sure the sleep is in game loop and not on the frame, one way to do this is create two threads at initialization, one for the frame and the other for the logic, then just let the game loop handle input and output while the display thread simply displays (i believe this how most game engines work). Also make sure neither thread is linked in any or the sleeping thread will affect the display thread.
I found the answer to my problem. The class that was calling the loop, which was a JPanel, didn't repaint when resized, only when the loop told it to, which caused some periods where the JPanel wasn't painted too. I fixed this by overriding paintComponent.
i been working on a game with no bitmaps or anything, I'm using rectangles as objects and changing their color for their purpose like a red rectangles for player and gray rectangles for walls. My question is what is the right way to replace the rectangles with bitmaps/images?
I know to load Bitmaps you can just do this :
Bitmap randomBitmap = BitmapFactory.decodeResource(getResources(),
com.example.android4gametest.R.drawable.ic_launcher);
Should i load all my Bitmaps and pass them to their Classes or should i load the bitmap inside their class instead of passing it ? and how would i do that because i cannot use the BitmapFactory because i have no access to the getResources()! or should i load my bitmaps/images from my assets folder which i know i wont have the same "tools" you can say to mess with the bitmap.
MainActivity
public class MainActivity extends Activity {
Game theGame;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new Game(this));
}
}
The Game Panel
public class Game extends SurfaceView implements SurfaceHolder.Callback {
GameThread _thread;
public Game(Context context) {
super(context);
getHolder().addCallback(this);
setFocusable(true);
_thread = new GameThread(getHolder(), this);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
_thread.setRunning(true);
_thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
#Override
protected void onDraw(Canvas canvas) {
Log.d("OnDraw", "it is Drawing");
canvas.drawColor(Color.BLUE);
}
public void update() {
// TODO Auto-generated method stub
}
}
GameLoop Nothing here
public class GameThread extends Thread{
/*FPS Code*/
private final static int MAX_FPS = 30;
private static final int FRAME_PERIOD = 1000/MAX_FPS;
protected SurfaceHolder holder;
protected Game game;
private boolean isRunning = false;
public GameThread(SurfaceHolder _holder, Game _game) {
this.holder = _holder;
this.game = _game;
}
/**
* Returns True if the game is still running and False if the game is over
* #return
*/
public boolean isRunning() {
return isRunning;
}
/**
* Set to true for the game loop to start
* #param isRunning
*/
public void setRunning(boolean isRunning) {
this.isRunning = isRunning;
}
#Override
public void run() {
Canvas c;
Log.d("Pallyways", "Starting game Loop");
long beingTime;
long timeDiff;
int sleepTime;
int framesSkipped;
sleepTime = 0;
while(isRunning){
c = null;
try{
c = holder.lockCanvas();
synchronized(holder){
beingTime = System.currentTimeMillis();
framesSkipped = 0;
game.update();//Update
game.onDraw(c);//Redraw
timeDiff = System.currentTimeMillis() - beingTime ;
sleepTime = (int) (FRAME_PERIOD - timeDiff);
if(sleepTime>0){
try{
Thread.sleep(sleepTime);}
catch (InterruptedException e) {
e.printStackTrace();}
finally{}
}
while(sleepTime<0 && framesSkipped < 5){
game.update();
sleepTime+= FRAME_PERIOD;
framesSkipped++;
}
}
}finally{if(c!=null){
holder.unlockCanvasAndPost(c);
}
}
}
}
}
Hero Class I have not started but i would like to know how to load a bitmap on a class that is on a different Package
package com.example.android4gametest.Actors;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.example.android4gametest.R;
public class Hero {
//getContext() gives me an error and that is because it does not have a reference
private Bitmap hero = BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.ic_launcher);
public Hero(){
}}
Depending on the sizes/number of bitmaps, it may be fine to load them in the constructor of your Game class. Be aware though, if you're loading too many/too big bitmaps into memory at once, you may run into some OOM errors or a lag in when your first draw call gets made. You have to be sure you're nulling, recycling your bitmaps efficiently when you no longer need them. Struggled with this issue with my first game
Do not load the Bitmap in your game object's constructors. If any of those Bitmaps would be used by multiple objects (i.e. an enemy class), then if you loaded them in your object's constructors you would have multiple copies of the Bitmap in memory. This could lead to an OutOfMemoryException. Instead load your Bitmap outside of your constructors (in your game thread or game panel) and then pass the Bitmap objects to the constructors or setters and set your private Bitmaps that way. You'll only have to keep a limited number of Bitmaps in memory.
You may also want to consider a loading "screen" which displays a progress bar or spinner while you load those Bitmaps.
Where you load is not important. I think your main issue is accessing the resources. In a view, you can call:
getContext().getResources()
Edit:
So in the method signature of the constructor of Hero add Context as a parameter:
public Hero(Context context){
private Bitmap hero = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
}
DO NOT! use dynamic objects.. I mean Do not create dynamic objects in a game at all, these will trigger the GC and make everything stutter when it's running whenever it wants. You must take control over everything yourself and use static/final "objects" and arrays on the obstacles and enemies. The objects will be loaded on to the heap at startup, which means that you will have them loaded until the app is shut down. Therefore you must find the balance between what to have in these static objects and not, but it's easy when you have found it.
The bitmaps should be loaded outside these static non-dynamic objects, the objects should only do the calculations.
And never use any unnessesary calculations, loops or Thread.sleep in between your
c = holder.lockCanvas(); and holder.unlockCanvasAndPost(c); like you're doing in your code.
This can and will finally make the game flicker.
Regards,
Me
does anyone knows how to use the blackberry JDE API to create a screen slide animation similar to Featured Items screen in the Blackberry App World? I am aware that in blackberry 5.0, there are some transition apis to perform that. But I am looking to do it for version 4.6 OS. It has the nice scrolling effect using the scrolling ball in blackberry bold.
Thanks.
As an alternative to the screenshot/Bitmap approach...
In the paint method of your screen you can use Graphics.pushContext(..) to push a clipping region and drawing offset. For best results, you'll want to do the transition in a runnable, and synchronize on the event lock. This will ensure that your screen can be dismissed in the middle of a transition.
Rough example:
class TransitionScreen extends Screen {
private int transitionOffset;
private boolean isTransitionHorizontal;
private ScreenTransition currentTransition;
public TransitionScreen(boolean isTransitionHorizontal) {
this.isTransitionHorizontal = isTransitionHorizontal;
transitionOffset = getTransitionMaximum(); // So the screen starts offset
}
protected void paint(Graphics graphics) {
// use transitionOffset as x or y depending on isTransitionHorizontal
graphics.pushContext(...);
}
protected void onExposed() {
transitionToOffset(0);
}
protected void onObscured() {
int target = getTransitionMaximum();
transitionToOffset(target);
}
private int getTransitionMaximum() {
return isTransitionHorizontal ? Display.getWidth() : Display.getHeight();
}
private void transitionToOffset(int target) {
if (currentTransition != null) {
currentTransition.stop();
}
currentTransition = new ScreenTransition(target);
getApplication().invokeLater(currentTransition);
}
}
class ScreenTransition implements Runnable {
private boolean animating;
private int target;
public ScreenTransitionUpdater(int target) {
this.target = target;
}
public void stop() {
animating = false;
}
public void run() {
while(animating) {
Object eventLock = getApplication().getEventLock();
synchronized(eventLock) {
// Interpolate myOffset to target
// Set animating = false if myOffset = target
invalidate();
}
}
}
}
No need to mark animating as volatile as it is ignored on this platform.
Maybe use a timer to change the coordinate position of the images in the paint method