I have a game engine that tries to load resources efficiently by storing Images in a HashMap. When I want to load an image for a Sprite object, I simply say Sprite.image = LOAD_IMAGE(imageName);
Now I'm making a map editor for this game. I'd like to be able to rotate certain tiles, such a tile of a house to face different directions through Java Image manipulation. I have that working; however, the error arises in the way I set the image to the new rotated Image. I say Sprite.image = rotateImage(Sprite.image); This leads to ALL TILES of the same type to have the same new rotate image.
What can I implement into my game so that each Sprite can be rotated and not affect the other Sprite's Images? I would still like to also keep my HashMap if possible, as I think it would really increase the efficiency of my game.
This is how I implement my rotation:
terrain.terrainImage = ImageManipulator.mirror(currentTile.terrain.terrainImage, false);
This is my "ImageBank":
public HashMap images = new HashMap(30);
public synchronized Image getImage(String imgName) {
// Check if the HashMap images already has the specified image
// by checking for the image name.
if (imgExists(imgName)) {
// Sprite already loaded.
return hm.get(imgName);
} else {
// Sprite hasn't been loaded yet.
Image img;
img = loadImage(imgName);
if (img == null) {
// An error occured, couldn't load sprite.
return null;
} // else move on
// save the loaded sprite (and now transparent) into the hashmap
hm.put(imgName, img);
// and then return the sprite
return img;
}
}
Either you store for each tile if and by which angle it is rotated (and than rotate it each time you draw it) or you store rotated copies on the image.
I recommend storing rotated versions.
Related
I'm making a 2d topdown view game where the camera follows the player so that the player is always in the center of the screen. I'm using Swing for all of my Graphics at the moment. I currently have a set of tiles that I use to create Sprites which all contain an Image. I can display all of the Images in the Sprites, but player movement always jerks the camera around, and I thought of combining all of my smaller Images into a large one, several times the screen, which I can take neat sub-tile precision slices of for smoother camera movement. When trying to do this I couldn't quite figure out how a Raster is constructed so I thought I might as well ask if better methods are available. My current attempt for creating the big Image looks something like this:
private Image prepareBackground() {
Raster raster = background.getData();
int[] rgb = new int[background.getColorModel().getNumComponents()];
for( int i=0;i< everySprite.length;++i){
for(int j=0;j<everySprite[0].length;++j){
Raster tileImage = ((BufferedImage)everySprite[i][j].getImage()).getData();
for(int k=0;k< tileImage.getHeight();++k){
for(int l =0;l<tileImage.getWidth();++l){
int[] values = tileImage.getPixel(k,l, rgb);
//how do I set the new pixel?
}
}
}
}
}
When I got this far I realized there are no setters for a Raster's single pixel, just getters.
I want to flip a bitmap that moves around with canvas or any other tool that does not contain creating new bitmaps. I managed to flip the bitmap with this code:
c.save();
c.scale(-1, 1,screenw/2,screenh/2);
c.drawBitmap(mob, position.x,position.y,null);
c.restore();
But that also flips the position of the bitmap, meaning that if it was moving left, after flipping it - it will move right. I don't want that, I want the position to be moving the same, only that the bitmap will be flipped. Any ideas?
public void Draw(Canvas c){
UpdateAll();
Matrix m = new Matrix();
m.setScale(-1, 1,mob.getWidth()/2,mob.getHeight()/2);
m.postTranslate(position.x, position.y);
c.drawBitmap(mob,m,null);
}
the mob is the bitmap, make sure to create the Matrix outside the draw function unlike in this code.
OK so I'm really confused I've rotated sprites before and had no problem such as rotating a boat as it moves through an ocean, but for some reason I'm having a really big problem this time. So I create a texture in an assets file, but not static textures. I load the texture using the following:
class Assets{
Texture img;
public Assets(){
img = new Texture(Gdx.files.internal("images/PNG.png")
And then I call the assets in the main class by calling:
Assets assets = new Assets()
And then I have a class that is an animator just for this main character because his animation is so different and varied from other characters.
class Animations{
Guy MYGUY;
Texture firstTexture;
ArrayList<Texture> running;
Sprite CurrentSprite;
public Animations(Texture standingStill, Guy myGuy){
MYGUY = myGuy;
firstTexture = standingStill;
running = new ArrayList<Texture>();
running.add(firstTexture);
CurrentSprite = new Sprite(firstTexture);
public void update (int direction, int state){
CurrentSprite.setPosition(MYGUY.X, MYGUY.Y)
// I have a switch here, but it does nothing yet because I haven't added in different actions for the character.
//However I do have a switch for direction, because that is important right now
switch(state){
case Guy.LEFT:
CurrentSprite.set rotation(180);
//yes there are more, but even rotating 180 won't work correctly
}
Then I have a renderer class to draw everything, i have the object MyGuy in an object for the world called myLand and I draw it with:
myLand.GUY.animation.CurrentSprite(batch);
So my problem arises on the rotation, whenever it rotates 180 degrees it seems to always rotate around the coordinates (0, 0) instead of the center of the sprite. So it usually ends up where I move like five to the right, but then if I try to go left it does double the distance backwards, but the camera position stays the same, and the guy usually disappears off the left or right side of the screen.
Try use rotate(...)method instead of setRotation(...).
With setOrigin(widthSprite\2, heightSprite\2)
That action rotate sprite itself.
Try
sprite.setOriginCenter();
This should help
Instead of rotating the sprite, just flip it with this single line:
CurrentSprite.flip(true, false);
the first boolean is X flip (that's what you want to set as true when going left) and the second is the Y flip.
I have 2 images as following:
I would like to combine them automatically, hopefully it can be done in Java
How to detect the pixel location and correct edges to combine both images, due to both images have overlapping and without knowing which is the correct edges to combine? Any algorithm can be provided?
ImageJ is a very good java image processing library. It may have plugins out there to do this already so perhaps worth a check.
I would start by trying to find a location in both images that is the same. Do a line profile across both images vertically and see if the pixel values and y values are the same. If the images are exactly the same in only one location then it should be easy. If there are multiple locations where the pixels are the same or the pixels in the y direction are never the same then I think your problem may not have a uniquie solution.
Here is some code to get you started
public class CombineImages implements PlugIn
{
#Override
public void run(String arg0) {
// TODO Auto-generated method stub
}
public ImagePlus combineImages(ImageProcessor ip1, ImageProcessor ip2){
//Get a line of Y pixel values for the first image for each x position and add them to a list
ArrayList<Roi> roiList1 = new ArrayList<Roi>();
for(int i=0; i<ip1.getWidth()-1; i++){
Roi roi = new Roi(i,i+1,1, ip1.getHeight());
roiList1.add(roi);
}
//Get a line of Y pixel values for the second image for each x position and add them to a list
ArrayList<Roi> roiList2 = new ArrayList<Roi>();
for(int i=0; i<ip2.getWidth()-1; i++){
Roi roi = new Roi(i,i+1,1, ip2.getHeight());
roiList2.add(roi);
}
//Check if these are the same and return the X values for both images that these correspond to
//You can then crop and combine the pixel values
return null;
}
}
I need to let a user move an image around on the screen and resize it too.
That part I have accomplished already.
The part that I can't figure out is how to, upon taking a picture, freeze the moveable/resizable Image on the photo-image than merge the two together to make 1 Bitmap.
I don't really have any "snippets" of code to post. I am just hoping some people may have had an experience with this before and might care to shed some light.
EDIT. I understand that when I take the picture the image is already frozen on the screen. At that instance I capture the items location on canvas. What I need to do is to take the canvas that I already have something drawn on and somehow overlay that onto another canvas that I assigned the photo too.
EDIT #2
OK ladies and gentlemen. I figured it out. Here is the code for making an overlay for the camera (as described by mmeyer.)
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c) {
Context ct = new Context;
RelativeLayout relativeview = new RelativeLayout(ct);
if (imageData != null) {
Context ct = HagsCamera.this;
new Intent(ct, PreviewandSend.class);
Bitmap photo = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
int picwidth= (photo.getWidth()/2);
int picheight = (photo.getHeight()/2);
Bitmap photocopy = Bitmap.createScaledBitmap(photo, picwidth, picheight, false);
Canvas c2 = crv.canvastoreturn;
c2.setBitmap(photocopy);
//photo.recycle();
ImageView newImage = new ImageView(ct);
relativeview.addView(newImage);
relativeview.draw(c2);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
photo.getWidth()/2, photo.getHeight()/2);
relativeview.setLayoutParams(lp);
Good luck to you all. I hope this helps save alot of headaches.
In short: Make a Bitmap of your picture.
Make a canvas for your overlay and toss your stuff up on there
Get a copy of your overlay's canvas
.setBitmap() that canvas and set it to your photo-bitmap.
Make a RelativeLayout and add a new ImageView to that.
Draw your canvas on the ImageView.
then figure out your layout parameters for your RelativeLayout.
Now that I think about it, maybe you can just set the top layer canvas to your Photo's Bitmap...and just save that...... You can test that yourself.
I done something in the past where I have an overlay view on top of a surface view which holds camera preview.
When the user wants to capture the pic, I take the next preview frame from Camera.PreviewCallback.onPreviewFrame() and then convert that from YUV to bitmap.
I then get a canvas against that bitmap and pass that canvas to the Draw() method of the custom view class that is my overlay view, and it will draw whatever it had been drawing onscreen to my new canvas! I can then take the bitmap and save it a jpg/png to SD.
Note that within that custom view class it has to deal with scaling due to the fact that the canvas it gets when being asked to draw on screen is a different size than the canvas it is given when asked to draw onto the canvas from the preview frame.
Beware of preview sizes and out of memory errors here though as many phones have very large default preview frame sizes and making bitmaps to draw onto with canvas can chew up memory fast. Learn about how to use Bitmap.recycle() and how to monitor native heap to combat these.
Hope that helps.
After reading the follow up comments and the issue youre having with black/blank images I decided to post some psuedo code to show how I'm doing this...
// decode the camera data into an immutable bitmap
Bitmap raw = CameraHelper.decodeYUV(frameInfo.frameData, frameInfo.frameSize.x, frameInfo.frameSize.y);
frameInfo.frameData = null; // allow large bytearry to to get gc'd
Bitmap cameraPic = raw.copy(Bitmap.Config.RGB_565, true); // make a mutable copy
Canvas c2 = (new Canvas(cameraPic)); // create a canvas from the camera pic
raw.recycle(); // we're done with raw bitmap now and can reclaim from native heap.
reticleOverlay.draw(c2); // reticle overlay is a class that implements View
String filename = acquireNextShotFilename()); // get a filename to write to SD
FileOutputStream fileoutputStream;
try {
fileoutputStream = new FileOutputStream(filename);
} catch (FileNotFoundException e) {
MyLogger.e("Couldnt open fileoutputstream: ", e);
throw e;
}
cameraPic.compress(CompressFormat.PNG, 100, fileoutputStream);
cameraPic.recycle();
try {
fileoutputStream.flush();
fileoutputStream.close();
} catch (IOException e) {
MyLogger.e("Error writing to file: ", e);
fileoutputStream.close();
}