I'm using Java to create a game, and I'm using TexturePaint to texture areas in the background. Performance is fine using java.awt.TexturePaint, however, I want to have areas having an inherent rotation, so I tried implementing a custom Paint called OrientedTexturePaint:
public class OrientableTexturePaint implements Paint {
private TexturePaint texture;
private float orientation;
public OrientableTexturePaint(TexturePaint paint, float orientation)
{
texture = paint;
this.orientation = HelperMethods.clampRadians((float)Math.toRadians(orientation));
}
public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints)
{
AffineTransform newTransform = (AffineTransform)xform.clone();
newTransform.rotate(orientation);
return texture.createContext(cm, deviceBounds, userBounds, newTransform, hints);
}
public int getTransparency()
{
return texture.getTransparency();
}
}
Only problem is, there's a huge performance hit: the frame rate drops from a comfortable (capped) 60fps to about 3fps. Furthermore, if I implement this as a pure wrapper to TexturePaint - without creating the new transform, simply passing the arguments to TexturePaint's methods and returning what TexturePaint returns, I get the same result.
i.e.:
public class MyTexturePaint implements Paint {
private TexturePaint texture;
public OrientableTexturePaint(TexturePaint paint, float orientation)
{
texture = paint;
}
public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints)
{
return texture.createContext(cm, deviceBounds, userBounds, xform, hints);
}
public int getTransparency()
{
return texture.getTransparency();
}
}
performs massively worse than TexturePaint does. How come, and is there any way to get around this?
I would paint the rotated portion to a BufferedImage and then paint that to the background. Then you only have to update the BufferedImage when there is a change to the rotated portions.
If you don't create a cache this way, if you do the painting from scratch each time, you have to consider the pipeline of the paint model and how complex that is. Performance is about reducing the bottlenecks in the rendering pipeline, and passing everything through a texturepaint process sounds like a massive bottleneck. Textures are to be created once, used often, not created often, used once.
Related
I'm trying to create a solar system using processing but I'm stuck at trying to set an image instead of using the java standard elipse image.
I started this at school and it consisted of an ellipse rotating around another ellipse.
package processing;
import processing.core.PApplet;
import processing.core.PImage;
public class SolarSystem extends PApplet{
PImage background;
Pianets earth;
public void settings() {
size(650,500);
}
public void setup() {
background = loadImage("C:\\background\\bg.jpg");
earth = new Pianets(this, width/2,height/2,40, 200, 0);
}
public void draw() {
background(background);
earth.showEarth();
earth.rotateEarth(0.007f);
}
public static void main(String[] args) {
PApplet.main("processing.SolarSystem");
}
}
Planets class
package processing;
import processing.core.PApplet;
public class Pianets {
PApplet vis;
float x0,y0; //centre
float diam;
float r; //distance from the centre
float alpha; //rotation angle
public Pianeti(PApplet applet, float x, float y, float diam,float r, float alpha){
vis = applet;
this.x0=x;
this.y0=y;
this.diam=diam;
this.r=r;
this.alpha=alpha;
}
void rotateEarth(float deltaAlpha){
alpha +=deltaAlpha;
}
void showEarth(){
//drawing the body of object at the centre
vis.ellipse(x0, y0, diam, diam);
float x = x0 + r*vis.cos(alpha);
float y = y0 + r*vis.sin(alpha);
vis.ellipse(x,y,diam,diam);
}
I created two images on paint that are the earth and the sun but I don't know how to set the image up.
Questions like this are best answered by looking at the Processing reference. There's an Image section that lists a loadImage() function for loading an image file, and an image() function for drawing it. Please read those.
You should also get into the habit of breaking your problem down into smaller pieces. For example, instead of posting your whole project (which has nothing to do with loading images right now), try to create a smaller example program that just shows a single image. Get that working perfectly before moving on. Then if you're confused about something, you can post a MCVE along with a specific technical question.
Shameless self-promotion: I wrote a tutorial on images in Processing available here.
I'm making a game with Libgdx and I'm using isometric perspective.
I have a problem when rendering my character because the map is loaded from Tiled Map Editor and character is a Sprite.
If I have a wall on layer 0 of the map, when drawing the wall before the Sprite, if the sprite is behind the wall, we will see the Sprite instead of wall (we should see the wall), if rendering the Sprite first, we will see the wall instead of the Sprite when the sprite is in front of the wall (we should see the Sprite). Any idea about fixing this?
I haven't really worked with tiled maps, but I think it goes something like this.
First, in TileEd, create an object layer that will be used for your character sprite. So the layer should be between background stuff and stuff that should obscure your player. Name it something like "characters".
Then, create a MapObject subclass that can render a sprite. Something like this:
public class SpriteMapObject extends MapObject {
private Sprite sprite;
public SpriteMapObject (Sprite sprite) {
this.sprite = sprite;
}
#Override
public Color getColor () {
return sprite.getColor();
}
#Override
public void setColor(Color color){
sprite.setColor(color);
}
public void render(Batch batch){
Color spriteColor = sprite.getColor();
float originalAlpha = spriteColor.a;
spriteColor.a *= getOpacity();
sprite.draw(batch);
spriteColor.a = originalAlpha;
}
}
Now after you load your map and your sprite, you can put the sprite on that layer you prepared:
map.getLayers().get("characters").add(new SpriteMapObject(playerSprite));
You also need to subclass the map renderer so it will render the sprite for you. Use your subclassed version instead of the original. For instance:
public class SpritesOrthogonalTiledMapRenderer extends OrthogonalTiledMapRenderer {
//Override whichever constructor(s) you need
public SpritesOrthogonalTiledMapRenderer (TiledMap map, Batch batch) {
super(map, batch);
}
#Override
public void renderObject(MapObject object) {
super.renderObject(object);
if(object instanceof SpriteMapObject) {
((SpriteMapObject) object).render(batch);
}
}
}
That's the basics of how it works. But if you want your player to be able to be in front or behind of a wall like you described, then you will need to create multiple extra layers, and move your sprite object to different layers when necessary.
Looks to me like Libgdx could use a feature enhancement to OrthogonalTiledMapRenderer so it can draw objects automatically merged into a TileLayer and inserting them into the draw order based on row.
I found an "answer" somewhere else so I share it with you so if any1 else had the problem:
- get players tile location.
- get each tile in that stack ( aka, get a reference to every tile in that cell across each layer.
- check for visibility exceptions on each of those tiles. Store exceptions as properties defined in Tiled. ( will cover properties shortly )
- handle accordingly, most likely by raising or lowering the players render layer for that frame.
I'm working on a Java based game where I need to model some basic shapes. The implementation I have at the moment has a lot of duplicated attributes across shapes of the same dimensions.
Example, I have an Interactive Rectangle which is involved in Box2d world and I have a Background Rectangle which is not involved in Box2d world. But both classes need a width and height defined.
Does anyone know a better way to model this data?
Current implementation ..
Mock idea for new implementation, however Interactive and Background can only inherit from one parent.
The reason why I have Interactive and Background classes is so I can loop through my objects like below.
for (Background bgShape : getLevel.getBGShapes()){
bgShape.draw(
gl2,
new Vec3(
bgShape.getPosition().x,
bgShape.getPosition().y,
bgShape.getPosition().z));
}
for (Body body = world.getBodyList(); body != null; body = body.getNext()) {
Interactive iaShape = (Interactive) body.getUserData();
iaShape.draw(
gl2,
new Vec3(
body.getPosition().x,
body.getPosition().y,
0.0f));
}
Also Interactive class defines a number of attributes which are not present in Background,
public abstract class InteractiveShape extends Shape {
private String bodyType;
private float density;
private float friction;
private float restitution;
private boolean fixedRotation;
private Body body;
}
2nd example is much better asRectangle is really a shape, but has additional data (width and height)
I don't think Iteractive and Background are necessary unless they add any additional operations (which from the picture they do not).
I have a BufferedImage displayed in a JFrame through my own class. I opted to display the BufferedImage using my own class so I can scale it. My paintComponent and update
public class MyBuffIm{
public void paintComponent(Graphics canvas) {
if (bi == null) {
} else {
//bi, maxWidth, and maxHeight were passed to constructor
canvas.drawImage(bi, 0, 0, maxWidth, maxHeight, null);
}
}
public void update(Graphics canvas) {
super.update(canvas);
if(bi != null){
//Got this from some tutorial in the net.
//Done out of desperation :|
paintComponent(bi.getGraphics());
}
}
}
I overrode update since the docs are saying something like "If this component is not a lightweight component, the AWT calls the update method in response to a call to repaint". I'm not exactly sure if my component is lightweight or not.
In any case, I have the following code in my Runnable (does not work as I expect it to):
BufferedImage p = SomeMyBuffIm.getBuffIm();
Vector<Point> randomPixels = getRandomPixels(500);
int limit = randomPixels.size()
for (i = 0; i < limit; i++) {
Point rp = randomPixels.get(i)
p.setRGB(rp.x, rp.y, Color.red.getRGB());
}
SomeMyBuffIm.repaint();
mainFrame.repaint(); //JFrame call to repaint
I'd like to think that, since I'm scaling my image, I just can't discern the difference between the new and old images. But I've tried the largest values for getRandomPixels still to no effect. My test image, by the way, is just a white sheet so red pixels should stand out in it.
Anything wrong I'm doing?
I overrode update since the docs are saying something like "If this component is not a lightweight component, the AWT calls the update method in response to a call to repaint". I'm not exactly sure if my component is lightweight or not.
No you should NOT override update(). You would do that with AWT but not with Swing.
If you update the BufferedImage then all you need to do is invoke repaint() on your instance of the MyBuffin class.
If you need more help than post your SSCCE that demonstrates the problem.
In the Android MapsDemo available in Eclipse for the Google API, they create an inner class SmoothCanvas in MapViewCompassDemo.java. Within this class the re-implement seemingly every method and reroute it to a delegate instance of Canvas.
static final class SmoothCanvas extends Canvas {
Canvas delegate;
private final Paint mSmooth = new Paint(Paint.FILTER_BITMAP_FLAG);
public void setBitmap(Bitmap bitmap) {
delegate.setBitmap(bitmap);
}
public void setViewport(int width, int height) {
delegate.setViewport(width, height);
}
...
What is the point of the delegate in this instance?
The value of delegate is passed in to dispatchDraw. The SmoothCanvas class is a wrapper around delegate. By delegating, the Canvas implementation passed to dispatchDraw does all the heavy lifting. The wrapper just allows the injection of the smoothed paint without implementing all the logic of Canvas.
The key point of delegating in that instance is:
private final Paint mSmooth = new Paint(Paint.FILTER_BITMAP_FLAG);
FILTER_BITMAP_FLAG bit. Filtering affects the sampling of bitmaps when they are transformed. Filtering does not affect how the colors in the bitmap are converted into device pixels. That is dependent on dithering and xfermodes.
By activating that flag, drawing bitmaps will basically increase its performance. You will in the example that mSmoth is used in every drawBitmap call.