I am trying to convert some (ugly looking) code into functions, such that everything is better managable. However I have come to a problem, current code:
int red = card.getColor().getRed();
int green = card.getColor().getGreen();
int blue = card.getColor().getBlue();
Color color = new Color(red, green, blue);
int width;
int height;
int xOffset;
int yOffset;
int border;
//Whole card
width = CARD_DIMENSION.width;
height = CARD_DIMENSION.height;
xOffset = 0;
yOffset = 0;
border = 5;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < border || dy < border) {
g2d.setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
else {
g2d.setColor(new Color(red, green, blue, 192 - Math.min(dx, dy)));
}
g2d.drawLine(x + xOffset, y + yOffset, x + xOffset, y + yOffset);
}
}
I would have to copy this everytime I want to draw some new rectangle. At first sight it isn't hard to put it in a function, however these lines:
if (dx < border || dy < border) {
g2d.setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
else {
g2d.setColor(new Color(red, green, blue, 192 - Math.min(dx, dy)));
}
They make it hard since I use dx and dy there.
Now I have come up with a proposed solution which I would want to use with anonymous inner classes and overriding the two functions:
private abstract class CustomRectangle {
protected final int width;
protected final int height;
protected final int xOffset;
protected final int yOffset;
protected final int borderSize;
public CustomRectangle(final int width, final int height, final int xOffset, final int yOffset, final int borderSize) {
this.width = width;
this.height = height;
this.xOffset = xOffset;
this.yOffset = yOffset;
this.borderSize = borderSize;
}
abstract void inBorder();
abstract void outBorder();
public void draw(Graphics2D g2d) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder();
}
else {
outBorder();
}
g2d.drawLine(x + xOffset, y + yOffset, x + xOffset, y + yOffset);
}
}
}
}
But I am still afraid that it will be hard if not impossible to put in a formula using dx and dy (two local variables to the for loops).
I would appreciate it if anyone has any suggestions on either the general problem or on my own approach, because having several codeblocks that do essentially the same is just not acceptable.
Regards.
Related
I want to plot a given character into a console application, shaping an ellipse.
The problem I don't know how to solve is that I only know where to draw a character once I know the angle and the radius (with Sin and Cos functions), but then I may leave gaps.
It's even more complex, because I want to "draw" a filled ellipse, not only the border.
How can I do it?
The method I want is like this:
DrawEllipse(char ch, int centerX, int centerY, int width, int height)
Just an idea: I may write a loop with an inner loop in the rectangle area of the ellipse and determine if a position is inside or outside the area of the ellipse.
This will be a reasonable approximation.
public static void DrawEllipse( char c, int centerX, int centerY, int width, int height )
{
for( int i = 0; i < width; i++ )
{
int dx = i - width / 2;
int x = centerX + dx;
int h = (int) Math.Round( height * Math.Sqrt( width * width / 4.0 - dx * dx ) / width );
for( int dy = 1; dy <= h; dy++ )
{
Console.SetCursorPosition( x, centerY + dy );
Console.Write( c );
Console.SetCursorPosition( x, centerY - dy );
Console.Write( c );
}
if( h >= 0 )
{
Console.SetCursorPosition( x, centerY );
Console.Write( c );
}
}
}
To start off, here is how to draw a filled circle (assuming a 80x25 console window). Someone else might know the maths to allow width and height parameters.
static void DrawCircle(char ch, int centerX, int centerY, int radius)
{
for(int y = 0; y < 25; y++)
{
for(int x = 0; x < 80; x++)
{
char c = ' ';
var dX = x - centerX;
var dY = y - centerY;
if(dX * dX + dY * dY < (radius * radius))
{
c = ch;
}
Console.Write(c);
}
}
}
I'm creating a game using libgdx and I'm using stage and actors for the entities inside the game. but the problem is I cant keep the actor inside the stage or the screen. when i drag the actor in the lowest, highest, left most, or right most of my screen it goes out of the screen. I want it to stay inside the screen.
What should I do? please help.
this is the strip of code i use for dragging my actor
addListener(new DragListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
camera.unproject(dimension.set(x, y, 0));
System.out.println("clicked "+ x +","+y);
return true;
}
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
moveBy(x-(getWidth()/2),y-(getHeight()/3));
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
}
});
Stage does have getWidth and getHeight methods. They return world sizes managed by the internal Viewport. Window class has optional dragging behavior and keepWithinStage parameter.
This is a code snippet from LibGDX 1.8.0 (Window class):
public void touchDragged (InputEvent event, float x, float y, int pointer) {
if (!dragging) return;
float width = getWidth(), height = getHeight();
float windowX = getX(), windowY = getY();
float minWidth = getMinWidth(), maxWidth = getMaxWidth();
float minHeight = getMinHeight(), maxHeight = getMaxHeight();
Stage stage = getStage();
boolean clampPosition = keepWithinStage && getParent() == stage.getRoot();
if ((edge & MOVE) != 0) {
float amountX = x - startX, amountY = y - startY;
windowX += amountX;
windowY += amountY;
}
if ((edge & Align.left) != 0) {
float amountX = x - startX;
if (width - amountX < minWidth) amountX = -(minWidth - width);
if (clampPosition && windowX + amountX < 0) amountX = -windowX;
width -= amountX;
windowX += amountX;
}
if ((edge & Align.bottom) != 0) {
float amountY = y - startY;
if (height - amountY < minHeight) amountY = -(minHeight - height);
if (clampPosition && windowY + amountY < 0) amountY = -windowY;
height -= amountY;
windowY += amountY;
}
if ((edge & Align.right) != 0) {
float amountX = x - lastX;
if (width + amountX < minWidth) amountX = minWidth - width;
if (clampPosition && windowX + width + amountX > stage.getWidth()) amountX = stage.getWidth() - windowX - width;
width += amountX;
}
if ((edge & Align.top) != 0) {
float amountY = y - lastY;
if (height + amountY < minHeight) amountY = minHeight - height;
if (clampPosition && windowY + height + amountY > stage.getHeight())
amountY = stage.getHeight() - windowY - height;
height += amountY;
}
lastX = x;
lastY = y;
setBounds(Math.round(windowX), Math.round(windowY), Math.round(width), Math.round(height));
}
You can simplify this by clamping the X to 0 and stage.getWidth() - actor.getWidth() and doing the same for Y.
I am trying to properly rotate a sword in my 2D game. I have a sword image file, and I wish to rotate the image at the player's location. I tried using Graphics2D and AffineTransform, but the problem is that the player moves on a different coordinate plane, the Screen class, and the Graphics uses the literal location of the pixels on the JFrame. So, I realized that I need to render the sword by rotating the image itself, and then saving it into a pixel array for my screen class to render. However, I don't know how to do this. Here is the code for my screen rendering method:
public void render(double d, double yOffset2, BufferedImage image, int colour,
int mirrorDir, double scale, SpriteSheet sheet) {
d -= xOffset;
yOffset2 -= yOffset;
boolean mirrorX = (mirrorDir & BIT_MIRROR_X) > 0;
boolean mirrorY = (mirrorDir & BIT_MIRROR_Y) > 0;
double scaleMap = scale - 1;
for (int y = 0; y < image.getHeight(); y++) {
int ySheet = y;
if (mirrorY)
ySheet = image.getHeight() - 1 - y;
int yPixel = (int) (y + yOffset2 + (y * scaleMap) - ((scaleMap * 8) / 2));
for (int x = 0; x < image.getWidth(); x++) {
int xPixel = (int) (x + d + (x * scaleMap) - ((scaleMap * 8) / 2));
int xSheet = x;
if (mirrorX)
xSheet = image.getWidth() - 1 - x;
int col = (colour >> (sheet.pixels[xSheet + ySheet
* sheet.width])) & 255;
if (col < 255) {
for (int yScale = 0; yScale < scale; yScale++) {
if (yPixel + yScale < 0 || yPixel + yScale >= height)
continue;
for (int xScale = 0; xScale < scale; xScale++) {
if (x + d < 0 || x + d >= width)
continue;
pixels[(xPixel + xScale) + (yPixel + yScale)
* width] = col;
}
}
}
}
}
}
Here is one of my poor attempts to call the render method from the Sword Class:
public void render(Screen screen) {
AffineTransform at = new AffineTransform();
at.rotate(1, image.getWidth() / 2, image.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(at,
AffineTransformOp.TYPE_BILINEAR);
image = op.filter(image, null);
screen.render(this.x, this.y, image, SwordColor, 1, 1.5, sheet);
hitBox.setLocation((int) this.x, (int) this.y);
for (Entity entity : level.getEntities()) {
if (entity instanceof Mob) {
if (hitBox.intersects(((Mob) entity).hitBox)) {
// ((Mob) entity).health--;
}
}
}
}
Thank you for any help you can provide, and please feel free to tell me if theres a better way to do this.
You can rotate() the image around an anchor point, also seen here in a Graphics2D context. The method concatenates translate(), rotate() and translate() operations, also seen here as explicit transformations.
Addendum: It rotates the image, but how do I save the pixels of the image as an array?
Once you filter() the image, use one of the ImageIO.write() methods to save the resulting RenderedImage, for example.
I noticed that one of my methods is being very slow, with profiling I noticed it took up like 95% of the total execution time.
The class:
package gui;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
/**
*
* #author Frank
*/
public abstract class CustomRectangle {
protected final BufferedImage bufferedImage;
protected final int width;
protected final int height;
protected final int xOffset;
protected final int yOffset;
protected final int borderSize;
protected final boolean defaultOrientation;
protected Color color;
public CustomRectangle(final BufferedImage bufferedImage, final int width, final int height, final int xOffset, final int yOffset, final int borderSize, final boolean defaultOrientation) {
this.bufferedImage = bufferedImage;
this.width = width;
this.height = height;
if (defaultOrientation) {
this.xOffset = xOffset;
this.yOffset = yOffset;
}
else {
this.xOffset = bufferedImage.getWidth() - 1 - xOffset;
this.yOffset = bufferedImage.getHeight() - 1 - yOffset;
}
this.borderSize = borderSize;
this.defaultOrientation = defaultOrientation;
}
abstract public void inBorder(final int dx, final int dy);
abstract public void outBorder(final int dx, final int dy);
public void draw() {
if (defaultOrientation) {
drawDefaultOrientation();
}
else {
drawOppositeOrientation();
}
}
private void drawDefaultOrientation() {
int[] pixelArray = ((DataBufferInt)bufferedImage.getRaster().getDataBuffer()).getData();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder(dx, dy);
}
else {
outBorder(dx, dy);
}
pixelArray[(xOffset + x) + ((yOffset + y) * bufferedImage.getWidth())] = color.getRGB();
}
}
}
private void drawOppositeOrientation() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder(dx, dy);
}
else {
outBorder(dx, dy);
}
bufferedImage.setRGB(xOffset - x, yOffset - y, color.getRGB());
}
}
}
public void setColor(final Color color) {
this.color = color;
}
}
The slow method is the drawDefaultOrientation() method.
The scary part however is that even if I leave out all image-modifying code, then it is still slow.
The callee code:
new CustomRectangle(bufferedImage, 440, 180, 30, 490, 10, defaultOrientation) {
#Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - (int)Math.round(0.5 * Math.min(dx, dy))));
}
#Override
public void outBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 128 - (int)Math.round(0.5 * Math.min(dx, dy))));
}
}.draw();
There must be something going on as in any way this code should not take this long, even if it loops over x and y coordinates.
Some thought I had was that it could have to do with the Anonymous inner class + Override...
But hopefully someone with more knowledge can answer the question.
Try this: If red, green, blue don't change, then stop using an anonymous class, and in your implemented subclass do: (note, this might not work, but the basic idea should, if you can avoid constantly calling new Color by caching all the colors you might need)
private final Color[] colors;
public ImplementedCustomRectangle(...) {
super(...); // ... is not real code, I just don't want to copy/paste
colors = new Color[256];
for (i = 0; i < 256; i++) {
colors[i] = new Color(red, green, blue, i);
}
}
#Override
public void inBorder(final int dx, final int dy) {
int value = 255 - (int)Math.round(0.5 * Math.min(dx, dy));
setColor(colors[value]);
}
#Override
public void outBorder(final int dx, final int dy) {
int value = 128 - (int)Math.round(0.5 * Math.min(dx, dy);
setColor(colors[value]);
}
I've searched for some time already but haven't been able to find an answer to my question.
First I'll show two comparison pictures:
Method 1:
method 1 http://img713.imageshack.us/img713/3558/tcg6.jpg
Method 2:
method 2 http://img716.imageshack.us/img716/2755/tcg7.jpg
Method 1 has never given me any trouble, but I recently found out that it simply takes too long, and method 2 fixed that.
Code for method 1:
private void drawDefaultOrientation() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder(dx, dy);
}
else {
outBorder(dx, dy);
}
bufferedImage.setRGB(xOffset + x, yOffset + y, color.getRGB());
}
}
}
Code for method 2:
private void drawDefaultOrientation() {
DataBufferInt buffer = (DataBufferInt)bufferedImage.getRaster().getDataBuffer();
int[] pixelArray = buffer.getData();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder(dx, dy);
}
else {
outBorder(dx, dy);
}
pixelArray[(xOffset + x) + ((yOffset + y) * bufferedImage.getWidth())] = color.getRGB();
}
}
}
Please also note that the inBorder(dx, dy); and outBorder(dx, dy); set the color variable to a color with a Red, Green, Blue and Alpha value.
Callee code:
new CustomRectangle(bufferedImage, 220, 90, 15, 245, 5, defaultOrientation) {
#Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
#Override
public void outBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 128 - Math.min(dx, dy)));
}
}.draw();
I am really lost as to why the color difference is here.
I really hope anyone out there can help me. First I thought it had to do with the Alpha values, but as seen the alpha variaton still exists with method 2.
Regards.
I'd suggest, for "simple" thing (including boxes, shapes, gradients, and a lot more), you use directly the Java2D API. It will be both more efficient and simpler to write.
For example to fill a rectangle in your image with a color:
public void rectangle(Color color, float x1, float y1, float w, float h) {
Graphics2D g = bufferedImage.createGraphics();
g.setColor(color);
g.fill(new Rectangle2D.Float(x1, y1, w, h));
g.dispose(); // optional but releases the resource earlier
}
You can also use "g" to draw as much things as you need to do.