I have a list an element defined as such:
public List<Bullet> Bullets;
Bullet newBullet = new Bullet(0, 0, 0, 0, 0, 0, 0, 0);
When an onscreen button is pressed I run:
newBullet.setProperties((int)(CannonCenterX + CannonEndX), (int)(CannonCenterY + CannonEndY), (int)(25*scaleX), (int)(25*scaleY), CannonEndX, CannonEndY, screenWidth, screenHeight);
Bullets.add(newBullet);
That should change the properties of the newBullet element, and add a copy of it to the Bullet List. However once I do that the application crashes.
The threading part here:
// try locking the canvas for exclusive pixel editing on the surface
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
// update game state
this.gamePanel.update();
// draws the canvas on the panel
this.gamePanel.onDraw(canvas);
}
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
Generates an exception and the program closes. I have no idea why adding an already generated element to a list would crash the program. Any help is appreciated.
-Nathan
You need to create the list:
public List<Bullet> Bullets = new ArrayList<Bullet>();
Related
I am using SikuliX to check when a video on a website has ended.
I do this by comparing my region (which is my active web browser window) to a screen capture of the region I have taken while the video is playing.
If it doesn't match, that means the video is still playing and I will take a new screen capture, which will be run through the while loop again for comparison.
If it matches, it means the video has stopped and will exit the while loop.
It works when it first goes through the loop. The while loop returns null which means the video is playing. However, on the second time it loops, it will exit the while loop and tell me my video has stopped but it clearly hasn't.
Is my logic flawed?
// Get dimensions of the bounding rectangle of the specified window
WinDef.HWND hwnd = User32.INSTANCE.GetForegroundWindow();
WinDef.RECT dimensions = new WinDef.RECT();
// Get screen coordinates of upper-left and lower-right corners of the window in dimensions
User32.INSTANCE.GetWindowRect(hwnd, dimensions);
Rectangle window = new Rectangle(dimensions.toRectangle());
int x = window.x;
int y = window.y;
int width = window.width;
int height = window.height;
// Initialize screen region for Sikuli to match
Region region = new Region(x, y, width, height);
Robot robot;
Image image;
Pattern p;
try {
robot = new Robot(); // Gets and saves a reference to a new Robot object
} catch (AWTException e) {
throw new RuntimeException(
"Failed to initialize robot...");
}
robot.delay(3000); // Delay robot for 3 seconds
// Take a screen capture of the region
BufferedImage capture = robot.createScreenCapture(dimensions.toRectangle());
image = new Image(capture);
p = new Pattern(image);
region.wait(1.0); // Wait 1 second
// Check if region content is still the same
while (region.exists(p.similar((float) 0.99), 0) == null) {
System.out.println("Video is playing");
// Take a new screen capture of the region
BufferedImage captureLoop = robot.createScreenCapture(dimensions.toRectangle());
image = new Image(captureLoop);
p = new Pattern(image);
region.wait(1.0); // Wait 1 second
}
System.out.println("Video has stopped");
Instead of using while (region.exists(p.similar((float) 0.99), 0) == null), using while (region.compare(image).getScore() == 1.0) to compare the region with the screen capture gave the results I wanted.
I am trying to animate one of my TiledSprites after the player makes contact with the sprite. Here is my code so far:
levelObject = new AnimatedSprite(x, y, resourceManager.wooden_crate_region, vbom)
{
#Override
protected void onManagedUpdate(float pSecondsElapsed)
{
super.onManagedUpdate(pSecondsElapsed);
if (player.collidesWith(this))
{
addToScore(1);
final long[] CRATE_ANIMATE = new long[] { 1000, 1000, 1000, 10000};
this.animate(CRATE_ANIMATE, 0, 3, true);
this.setIgnoreUpdate(true);
}
}
};
But when I try to play the game, the player makes contact and goes through the sprite. Not sure whats going on. It does add the score, but no animation.
Any help would be appreciated.
remove the line
this.setIgnoreUpdate(true);
this line ignores any update on your object, means it won't animate it either.
I'm working on a drawing application and am pretty close to release but I'm having issues with the eraser part of the app. I have 2 main screens (fragments) one is just a blank white canvas that the user can draw on with some options and so on. The other is a note taking fragment. This note taking fragment looks like notebook paper. So for erasing on the drawing fragment, I can simply use the background of the canvas and the user wont know the difference. On the note fragment though I cannot do this beacuse I need to keep the background in tact. I have looked into PorterDuffer modes and have tried the clear version and tried to draw onto a separate bitmap but nothing has worked. If there was a way to control what gets draw ontop of what then that would be useful. I'm open to any suggestions, I can't seem to get anything to work.
Ive also played with enabling a drawing cache before erasing and that doesn't work. In addition I tried hardware enabling and that made my custom view behave oddly. Below is the relavent code. My on draw methods goes through a lot of paths because I am querying them in order to allow for some other functionallity.
#Override
protected void onDraw(Canvas canvas) {
//draw the backgroumd type
if(mDrawBackground) {
//draw the background
//if the bitmap is not null draw it as the background, otherwise we are in a note view
if(mBackgroundBitmap != null) {
canvas.drawBitmap(mBackgroundBitmap, 0, 0, backPaint);
} else {
drawBackgroundType(mBackgroundType, canvas);
}
}
for (int i = 0; i < paths.size(); i++ ) {
//Log.i("DRAW", "On draw: " + i);
//draw each previous path.
mDrawPaint.setStrokeWidth(strokeSizes.get(i));
mDrawPaint.setColor(colors.get(i));
canvas.drawPath(paths.get(i), mDrawPaint);
}
//set paint attributes to the current value
mDrawPaint.setStrokeWidth(strokeSize);
mDrawPaint.setColor(mDrawColor);
canvas.drawPath(mPath, mDrawPaint);
}
and my draw background method
/**
* Method that actually draws the notebook paper background
* #param canvas the {#code Canvas} to draw on.
*/
private void drawNoteBookPaperBackground(Canvas canvas) {
//create bitmap for the background and a temporary canvas.
mBackgroundBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBackgroundBitmap);
//set the color to white.
mBackgroundBitmap.eraseColor(Color.WHITE);
//get the height and width of the view minus padding.
int height = getHeight() - getPaddingTop() - getPaddingBottom();
int width = getWidth() - getPaddingLeft() - getPaddingRight();
//figure out how many lines we can draw given a certain line width.
int lineWidth = 50;
int numOfLines = Math.round(height / lineWidth);
Log.i("DRAWVIEW", "" + numOfLines);
//iterate through the number of lines and draw them.
for(int i = 0; i < numOfLines * lineWidth; i+=lineWidth) {
mCanvas.drawLine(0+getPaddingLeft(), i+getPaddingTop(), width, i+getPaddingTop(), mNoteBookPaperLinePaint);
}
//now we need to draw the vertical lines on the left side of the view.
float startPoint = 30;
//set the color to be red.
mNoteBookPaperLinePaint.setColor(getResources().getColor(R.color.notebook_paper_vertical_line_color));
//draw first line
mCanvas.drawLine(startPoint, 0, startPoint, getHeight(), mNoteBookPaperLinePaint);
//space the second line next to the first one.
startPoint+=20;
//draw the second line
mCanvas.drawLine(startPoint, 0, startPoint, getHeight(), mNoteBookPaperLinePaint);
//reset the paint color.
mNoteBookPaperLinePaint.setColor(getResources().getColor(R.color.notebook_paper_horizontal_line_color));
canvas.drawBitmap(mBackgroundBitmap, 0, 0, backPaint);
}
To all who see this question I thought I would add how I solved the problem. What I'm doing is creating a background bitmap in my custom view and then passing that to my hosting fragment. The fragment then sets that bitmap as its background for the containing view group so that when I use the PorterDuff.CLEAR Xfermode, the drawn paths are cleared but the background in the fragment parent remains untouched.
I have a Canvas on which I am drawing lines bewteen points in a onTouchEvent(). When the user makes an invalid selection on where to place the line, I draw a red line instead of a black one. However I want the red line to fade away over the next 500-1000ms.
I haven't been able to figure out how to do it, and if it is even possible to animate a single line inside a Canvas.
I have split the dots, the valid black lines and the invalid red line(s) between 3 different bitmaps inside my:
public void onDraw(Canvas canvas) {
// Fade Red Line
canvas.drawBitmap(fBitmap, 0, 0, null);
// Lines
canvas.drawBitmap(mBitmap, 0, 0, null);
// Dots
canvas.drawBitmap(iBitmap, 0, 0, null);
}
and inside my onTouch function are my drawLines().
I was wondering if I can use an AlphaAnimation for this, or if I have to use a timer system to loop over the fBitmap with the red line I want to fade out over time.
Any Ideas?
EDIT: Okay here's how I eventually solved it after coming back to it a year later:
I implemented a SurfaceView and created a thread to continuously update the Canvas.
#Override
public void run() {
while (isRunning) {
if (!surfaceHolder.getSurface().isValid()) {
continue;
}
decreaseLineOpacity();
drawLinesInvalid();
/* Other things to draw*/
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawBitmap(fBitmap, centerPointWidth, centerPointHeight, null);
// mBitmap is the middleground with the line that fades away.
// and is bound to mCanvas for drawing
canvas.drawBitmap(mBitmap, centerPointWidth, centerPointHeight, null);
canvas.drawBitmap(iBitmap, centerPointWidth, centerPointHeight, null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
And then the methods that take care of changing the opacity and drawing the line, I store each line I draw in a Queue, until it reaches an opacity of 0, and then I remove it so only the lines that need to be animated are left:
private void drawLinesInvalid() {
Iterator<int[]> iterator = invalidLines.iterator();
// Loop through each element in the Queue, delete it from the bitmap with the porter
// duff mode to keep the transparancy of the layer. Then draw line with the given opacity
while (iterator.hasNext()) {
int[] invalidLine = iterator.next();
float[] line = {invalidLine[1], invalidLine[2], invalidLine[3], invalidLine[4]};
Xfermode originalXfermode = paint.getXfermode();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mCanvas.drawLines(line, paint);
paint.setXfermode(originalXfermode);
paint.setColor(Color.RED);
paint.setAlpha(invalidLine[0]);
mCanvas.drawLines(line, paint);
}
}
// Call this function in the onTouch method
private void addLineToInvalidList(float[] line) {
// Store each line a queue with its current opacity
int[] lineWithOpacity = new int[5];
lineWithOpacity[0] = 250;
lineWithOpacity[1] = (int) line[0];
lineWithOpacity[2] = (int) line[1];
lineWithOpacity[3] = (int) line[2];
lineWithOpacity[4] = (int) line[3];
invalidLines.add(lineWithOpacity);
}
private void decreaseLineOpacity() {
Iterator<int[]> iterator = invalidLines.iterator();
// Remove all lines that are finished animating (opacity = 0)
while (iterator.hasNext()) {
int[] line = iterator.next();
if (line[0] == 0) {
iterator.remove();
}
}
// Decrease opacity on lines that are left
iterator = invalidLines.iterator();
while (iterator.hasNext()) {
int[] line = iterator.next();
line[0] -= 10;
}
}
Considering you are drawing all three bitmaps on the same view, using an AlphaAnimation may be a bit tricky.
I would suggest spawning a thread that changes the alpha value of the invalid red line(s) bitmap over time (sleeping for set intervals with Thread.sleep). However, for this to perform well you should look into using a SurfaceView as calling postInvalidate multiple times may be quite costly (unless this is running on Android 3.0+ with hardware acceleration).
I'm trying to show the famous mouth opening/closing animation of the pacman character in a throwaway pacman game I'm making to teach myself game programming.
What I'm doing is drawing the open mouth image, then redrawing the closed mouth image at the exact same (x/y) location. But this doesn't work, and I just see the closed mouth animation all the time.
If I put this in a loop, the system just freezes and you see flickering where the open mouth image this, but you don't see the images being replaced.
I've tested and made sure that both images are being loaded correctly and as expected.
Here's my startAnim() function, its called when you double click at the applet:
public void beginGame() //Called from engine.java
{
isRunning=true;
repaint();
pacman.startAnim();
}
public void startAnim() //In different class, pacman.java
{
Image orig;
while (engine.isRunning)
{
orig=this.getCurrentImg();
draw(engine.getGraphics());
this.setCurrImg(currImg2);
this.draw(engine.getGraphics());
this.setCurrImg(orig);
this.draw(engine.getGraphics());
try
{
Thread.sleep(100);
}
catch (InterruptedException e) {}
}
}
public void draw(Graphics g) //Called from engine.paint()
{
g.drawImage(getCurrentImg(), getX(),
getY(), engine);
}
you have to sleep between the 2 images. otherwise you will only see the last image painted.
eg.
while( running )
{
image 1
draw
sleep
image 2
draw
sleep
}
something like this:
public void startAnim() //In different class, pacman.java
{
final int cnt = 2;
Image[] imgs = new Image[ cnt ];
int step = 0;
imgs[ 0 ] = closedMouthImage;
imgs[ 1 ] = openMouthImage;
while ( engine.isRunning )
{
this.setCurrImg( imgs[ step ] );
draw(engine.getGraphics());
step = ( step + 1 ) % cnt;
try
{
Thread.sleep(100);
}
catch (InterruptedException e) {}
}
}
As sfossen said, you need a delay between drawing the images.
A couple of other things to consider.
For smooth animation, you probably need more than just the "mouth open" and "mouth closed" images. You need two or three intermediate images.
To make resource management easier, you might want to put all of your animation frames together in a single, wide image, that will look like a "filmstrip". Then, to draw a frame, you use the (x, y) offset for the frame your interested in.
Finally, if you draw all the frames each time you go through the main loop of your program, Pac-Man will do a complete chomp every time you move him. You should think about drawing just one frame each time through the main loop and using a variable to track which frame you're on.
Example (pseudocode)
frameWidth = 32
frameIndex = 0
while(running) {
// Draw just the frame of your animation that you want
drawImage(pacmanX, pacmanY, filmStrip, frameIndex * frameWidth, 0, frameWidth, frameHeight)
frameIndex = (frameIndex + 1) % frameCount
// Update position of pacman & ghosts
// Update sound effects, score indicators, etc.
}