Shapes drawn at obscure positions - java

this is a really weird bug and I can't seem to figure it out. To simplify this, I have three classes: A Canvas class (which draws the object with Graphics2D.draw()) then lots ob furniture classes, which can be viewed as one because all they do is return different shapes. Last I have a CustomShape class, which lets me create a new Shape based on my existing other shapes. But the shapes are being drawn at weird places. The x any y coordinates do not match where the shape is being drawn.
Closet.java:
public class Closet {
double x, y, width, height, rotation;
Color color;
Closet() {
this.x = X;
this.y = Y;
this.width = 40;
this.height = 40;
this.rotation = 0;
this.color = Color.blue;
}
public Shape getShape() {
GeneralPath closetShape = new GeneralPath();
closetShape.append(new Rectangle2D.Double(0, 0, width, height), false);
closetShape.moveTo(0 , 0);
closetShape.lineTo(width, height);
closetShape.moveTo(0, height);
closetShape.lineTo(width, 0);
// transform:
AffineTransform t = new AffineTransform();
t.translate(x, y);
Rectangle2D umriss = closetShape.getBounds2D();
t.rotate(Math.toRadians(rotation),umriss.getX()+umriss.getWidth()/2,umriss.getY()+umriss.getHeight()/2);
return t.createTransformedShape(closetShape);
}
}
CustomShape.java
public class CustomShape {
double x, y, width, height, rotation;
Color color;
private Closet[] c;
CustomShape(Closet... elements) {
this.m = elements;
GeneralPath path = new GeneralPath();
Closet[] newC = elements.clone();
Arrays.stream(newC).forEach(e -> path.append(e.getShape(), false));
this.x = path.getBounds2D().getX();
this.y = path.getBounds2D().getY();
this.width = path.getBounds2D().getWidth();
this.height = path.getBounds2D().getHeight();
this.rotation = 0;
this.color = Color.blue;
}
public Shape getShape() {
GeneralPath path = new GeneralPath();
Arrays.stream(c).forEach(e -> path.append(e.getShape(), false));
AffineTransform t = new AffineTransform();
t.translate(x, y);
Rectangle2D umriss = path.getBounds2D();
t.rotate(Math.toRadians(rotation),umriss.getX()+umriss.getWidth()/2,umriss.getY()+umriss.getHeight()/2);
return t.createTransformedShape(path);
}
}

I found the solution: I had transformed these Shapes before adding them to the CustomShape. That is why the x and y coordinates were wrong.

Related

Libgdx - Parallax background set horizontally, can't implement scrolling up and down

I found a tutorial online to create a horizontally scrolling parallax background with this custom class:
public class ParallaxBackground extends Actor {
private float scroll;
private Array<Texture> layers;
private final int LAYER_SPEED_DIFFERENCE = 2;
float x, y, width, height, scaleX, scaleY;
float originX, originY, rotation;
float srcX, srcY;
boolean flipX, flipY;
private float speed;
public ParallaxBackground(Array<Texture> textures, HeroKnight player) {
layers = textures;
for(int i = 0; i <textures.size;i++){
layers.get(i).setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
}
scroll = 0;
speed = 0;
x = y = originX = originY = rotation = 0;
srcY = 0;
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
scaleX = scaleY = 1;
flipX = flipY = false;
}
public void setSpeed(float newSpeed){
this.speed = newSpeed;
}
public void update(float deltaTime) {
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.setColor(getColor().r, getColor().g, getColor().b, getColor().a * parentAlpha);
scroll+=speed;
srcX = scroll;
batch.draw(layers.get(0), x, y, originX, originY, width, height, scaleX, scaleY, rotation, (int)srcX, (int) srcY, layers.get(0).getWidth(), layers.get(0).getHeight(), flipX, flipY);
for(int i = 1;i<layers.size;i++) {
srcX = scroll + i*this.LAYER_SPEED_DIFFERENCE *scroll;
batch.draw(layers.get(i), x, y, originX, originY, width, height,scaleX,scaleY,rotation,(int)srcX,(int)srcY,layers.get(i).getWidth(),layers.get(i).getHeight(),flipX,flipY);
}
}
.
backgroundViewport = new ScreenViewport();
stage = new Stage(backgroundViewport);
Array<Texture> textures = new Array<Texture>();
for(int i = 1; i <= 5;i++){
textures.add(new Texture(Gdx.files.internal("images/"+ i+".png")));
textures.get(textures.size-1).setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
}
parallaxBackground = new ParallaxBackground(textures, player);
parallaxBackground.setSize(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
parallaxBackground.setSpeed(0);
stage.addActor(parallaxBackground);
In the render method:
stage.act();
stage.draw();
Eveything works well when you are moving left to right. However, on my background image there is water down, so logically I want the screen to show it when the player is on the lower platforms, and make it scroll higher so that the water disappears when you go up.
So the question is: how do I make the blue part visible when the player is lower, and scroll it to the red part when you go higher?

Multicolor Edge Draw Paint Transformer

Trying to draw a metro graph using JUNG.
Is it possible to draw an edge of straight line that uses 2 or more colors in parallel, using the transformer?
You could do something like this....
Copy and modify some code from the EdgeShape class (where it makes the Bowtie shape) modified to a rectangle, then set the edge fill paint, draw paint, and stroke to look like what you want
public class RectangleEdge<V,E> extends AbstractEdgeShapeTransformer<V,E> {
private static GeneralPath rectangle;
public RectangleEdge(int width) {
rectangle = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
rectangle.moveTo(0, width/2); // change points to make rectangle
rectangle.lineTo(1, width/2);
rectangle.lineTo(1, -width/2);
rectangle.lineTo(0, -width/2);
rectangle.closePath();
}
public Shape transform(Context<Graph<V,E>,E> context) {
return rectangle;
}
}
vv.getRenderContext().setEdgeShapeTransformer(new RectangleEdge<>(4));
vv.getRenderContext().setEdgeFillPaintTransformer(new ConstantTransformer(Color.red));
vv.getRenderContext().setEdgeStrokeTransformer(new ConstantTransformer(new BasicStroke(2)));
vv.getRenderContext().setEdgeDrawPaintTransformer(new ConstantTransformer(Color.blue));
Here's a picture:
ok, if you want a lot of colors, try this:
vv.getRenderer().setEdgeRenderer(
new NotSimpleEdgeRenderer(new Color[]{
Color.red, Color.blue, Color.pink, Color.green, Color.magenta,
Color.cyan, Color.black, Color.orange, Color.yellow
}));
vv.getRenderContext().setEdgeStrokeTransformer(new ConstantTransformer(new BasicStroke(2)));
public class NotSimpleEdgeRenderer<V,E> extends BasicEdgeRenderer<V,E> {
Color[] colors;
Shape[] shapes;
public NotSimpleEdgeRenderer(Color... colors) {
int count = colors.length;
this.colors = colors;
shapes = new Shape[count];
for (int i=0; i<count; i++) {
shapes[i] = new Line2D.Double(0, -count/2+(2*i), 1, -count/2+(2*i));
}
}
protected void drawSimpleEdge(RenderContext<V,E> rc, Layout<V,E> layout, E e) {
GraphicsDecorator g = rc.getGraphicsContext();
Graph<V,E> graph = layout.getGraph();
Pair<V> endpoints = graph.getEndpoints(e);
V v1 = endpoints.getFirst();
V v2 = endpoints.getSecond();
Point2D p1 = layout.transform(v1);
Point2D p2 = layout.transform(v2);
p1 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p1);
p2 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p2);
float x1 = (float) p1.getX();
float y1 = (float) p1.getY();
float x2 = (float) p2.getX();
float y2 = (float) p2.getY();
boolean edgeHit;
Rectangle deviceRectangle = null;
JComponent vv = rc.getScreenDevice();
if(vv != null) {
Dimension d = vv.getSize();
deviceRectangle = new Rectangle(0,0,d.width,d.height);
}
AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);
float dx = x2-x1;
float dy = y2-y1;
float thetaRadians = (float) Math.atan2(dy, dx);
xform.rotate(thetaRadians);
float dist = (float) Math.sqrt(dx*dx + dy*dy);
xform.scale(dist, 1.0);
Paint oldPaint = g.getPaint();
for (int i=0; i<shapes.length; i++) {
Shape edgeShape = shapes[i];
edgeShape = xform.createTransformedShape(edgeShape);
MutableTransformer vt = rc.getMultiLayerTransformer().getTransformer(Layer.VIEW);
edgeHit = vt.transform(edgeShape).intersects(deviceRectangle);
if(edgeHit == true) {
Paint fill_paint = colors[i];
if (fill_paint != null) {
g.setPaint(fill_paint);
g.fill(edgeShape);
}
Paint draw_paint = colors[i];
if (draw_paint != null) {
g.setPaint(draw_paint);
g.draw(edgeShape);
}
}
// restore old paint
g.setPaint(oldPaint);
}
}
}
and it looks like this:
I think you can do this with small modifications to the code samples I posted in previous answers.
I assume that you know what colors you want for each edge. Make a Map that has the mappings from each edge to the colors you want for that edge. Then modify the code I answered with to look like this:
public class NotSimpleEdgeRenderer<V,E> extends BasicEdgeRenderer<V,E> {
Map<E,Color[]> colorMap;
public NotSimpleEdgeRenderer(Map<E,Color[]> colorMap) {
this.colorMap = colorMap;
}
protected void drawSimpleEdge(RenderContext<V,E> rc, Layout<V,E> layout, E e) {
GraphicsDecorator g = rc.getGraphicsContext();
Graph<V,E> graph = layout.getGraph();
Pair<V> endpoints = graph.getEndpoints(e);
V v1 = endpoints.getFirst();
V v2 = endpoints.getSecond();
Point2D p1 = layout.transform(v1);
Point2D p2 = layout.transform(v2);
p1 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p1);
p2 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p2);
float x1 = (float) p1.getX();
float y1 = (float) p1.getY();
float x2 = (float) p2.getX();
float y2 = (float) p2.getY();
boolean edgeHit;
Rectangle deviceRectangle = null;
JComponent vv = rc.getScreenDevice();
if(vv != null) {
Dimension d = vv.getSize();
deviceRectangle = new Rectangle(0,0,d.width,d.height);
}
AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);
float dx = x2-x1;
float dy = y2-y1;
float thetaRadians = (float) Math.atan2(dy, dx);
xform.rotate(thetaRadians);
float dist = (float) Math.sqrt(dx*dx + dy*dy);
xform.scale(dist, 1.0);
Paint oldPaint = g.getPaint();
// get the colors for this edge from the map
Color[] colors = colorMap.get(e);
int count = colors.length;
// make the Shapes for this edge here
Shape[] shapes = new Shape[count];
for (int i=0; i<count; i++) {
// this code offsets the lines enough to see the colors
shapes[i] = new Line2D.Double(0, -count/2+(2*i), 1, -count/2+(2*i));
}
// iterate over the edge shapes and draw them with the corresponding colors
for (int i=0; i<shapes.length; i++) {
Shape edgeShape = shapes[i];
edgeShape = xform.createTransformedShape(edgeShape);
MutableTransformer vt = rc.getMultiLayerTransformer().getTransformer(Layer.VIEW);
edgeHit = vt.transform(edgeShape).intersects(deviceRectangle);
if(edgeHit == true) {
Paint fill_paint = colors[i];
if (fill_paint != null) {
g.setPaint(fill_paint);
g.fill(edgeShape);
}
Paint draw_paint = colors[i];
if (draw_paint != null) {
g.setPaint(draw_paint);
g.draw(edgeShape);
}
}
// restore old paint
g.setPaint(oldPaint);
}
}
}

Java - How to move a shape

So far I am just making a new Shape to "move" it. But is there a better way to change the position of a Shape in Java?
// Collision Shape
protected RectangularShape col;
public GameObject() {
col = new Ellipse2D.Double(x, y, ObjectSpriteManager.SIZE, ObjectSpriteManager.SIZE);
}
public void tick() {
x += velX;
y += velY;
col = new Ellipse2D.Double(x, y, ObjectSpriteManager.SIZE, ObjectSpriteManager.SIZE);
}
See the setFrame() methods of RectangulerShape. For example:
col.setFrame(x, y, width, height);

Collision detection, rectangle intersects at corner

I'm trying to learn how collision detection works in android and I am doing so using Android rectangles.
I need to be able to detect a collision of the second rectangles top, left and bottom walls but the issue is that the first rectangle is able to go straight in to the second rectangle through the top left corner.
Below is a snippet of the code that I am using:
Snippet from GameView2 class:
private Shape s1 = new Shape(this, Color.BLACK, 0, 100, 50, 50);
private Shape s2 = new Shape(this, Color.BLUE, 200, 100, 50, 50);
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
this.drawBackground(canvas);
s1.onDraw(canvas);
s2.onDraw(canvas);
s1.x+=s1.vx;
s1.y+=s1.vy;
//left wall collision
if(s1.x+s1.width==s2.x && s1.y+s1.height > s2.y && s1.y < s2.y + s2.height){
s1.vx = 0;
}
//top wall
else if(s1.y+s1.height==s2.y && s1.x+s1.width > s2.x && s1.x < s2.x+s2.width){
s1.vy = 0;
}
else{
s1.vx = 2;
}
}
Shape class:
public class Shape{
protected GameView2 game_view;
protected int x;
protected int y;
protected int vx;
protected int vy;
protected int width;
protected int height;
protected int color;
public Shape(GameView2 game_view, int color, int x, int y, int width, int height) {
this.game_view = game_view;
this.x = x;
this.y = y;
this.vx = 2;
this.vy = 0;
this.width = width;
this.height = height;
this.color = color;
}
public Rect getRect(){
return new Rect(x, y, x + width, y + height);
}
public void onDraw(Canvas canvas){
Paint paint = new Paint();
Rect rec = new Rect(x, y, x + width, y + height);
paint.setColor(color);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(rec, paint);
}
}
Here is a really simple algorithm for collision between two rectangles.
x1+width1 < x2 || x2+width2 < x1 || y1+height1 < y2 || y2+height2
If the statement above is true, no collision occurs. Else, the two rectangles are colliding.

Moving cube in opengl on android help

After a lot of trial and error I was able to draw a cube and a tile map for the cube to be infront of. I added input so that when you move your finger, the camera moves. But now I want to add the next step in my games progression. I want it to have my cube move to where i pressed my finger in 3d space. It sounds a bit difficult. What I wanted to do is have you use one finger to slide the camera around the map and the other to double tap and move. So far my cube jitters and wobbles in place but doesn't move to where I want it to go. Of course none of my code is perfect and my following of gluunproject might be far from correct. Here is my code so far
The cube creator and update code//its short
public shapemaker(int x, int y, int z,int width)
{
centerx =x;
centery =y;
centerz =z;
mysquare1= new square(centerx,centery,centerz-5,1,.0f,.0f,1f,"vert");
mysquare2= new square(centerx-1,centery,centerz-6f,1,.0f,1.0f,.0f,"side");
mysquare3= new square(centerx,centery,centerz-7,1,1.0f,.0f,.0f,"vert");
mysquare4= new square(centerx+1,centery,centerz-6f,1,.0f,.5f,.5f,"side");
mysquare5= new square(centerx,centery-1,centerz-6f,1,.5f,.5f,.0f,"horiz");
mysquare6= new square(centerx,centery+1,centerz-6f,1,.5f,.0f,.5f,"horiz");
}
public void updatecube(float x, float y, float z)
{
centerx =x;
centery =y;
centerz =z;
mysquare1= new square(centerx,centery,centerz-5,1,.0f,.0f,1f,"vert");
mysquare2= new square(centerx-1,centery,centerz-6f,1,.0f,1.0f,.0f,"side");
mysquare3= new square(centerx,centery,centerz-7,1,1.0f,.0f,.0f,"vert");
mysquare4= new square(centerx+1,centery,centerz-6f,1,.0f,.5f,.5f,"side");
mysquare5= new square(centerx,centery-1,centerz-6f,1,.5f,.5f,.0f,"horiz");
mysquare6= new square(centerx,centery+1,centerz-6f,1,.5f,.0f,.5f,"horiz");
}
public void drawcube(GL10 gl)
{
mysquare1.draw(gl);
mysquare2.draw(gl);
mysquare3.draw(gl);
mysquare4.draw(gl);
mysquare5.draw(gl);
mysquare6.draw(gl);
}
public float getcenterx()
{
return centerx;
}
public float getcentery()
{
return centery;
}
public float getcenterz()
{
return centerz;
}
Here is the actual implementation code , it is based off of googles intro to opengl
class ClearGLSurfaceView extends GLSurfaceView {
private static final String BufferUtils = null;
float x =0;
float y =0;
float z =0f;
float prevx=0;
float prevy=0;
GL10 mygl;
// GL gl;
float mywidth;
float myheight;
public ClearGLSurfaceView(Context context,float width, float height) {
super(context);
mRenderer = new ClearRenderer();
setRenderer(mRenderer);
mywidth = width;
myheight = height;
}
#Override
public boolean onTouchEvent(final MotionEvent event)
{
queueEvent(new Runnable() {
// Find the index of the active pointer and fetch its position
public void run()
{
float curx = event.getX();
float cury = event.getY();
final int action = event.getAction();
if(action == MotionEvent.ACTION_MOVE)
{
if(curx>prevx)
{
x-=.1f;
}
if(curx<prevx)
{
x+=.1f;
}
if(cury>prevy)
{
y+=.1f;
}
if(cury<prevy)
{
y-=.1f;
}
}
if(action == MotionEvent.ACTION_DOWN)
{
// GLU.gluUnProject(winX, winY, winZ, model,
// modelOffset, project, projectOffset, view, viewOffset, obj, objOffset)
vector2d moveto = new vector2d(0,0);
moveto = mRenderer.getworkcoords(curx,cury);
Log.i("move to ", "x "+moveto.x+" y "+ moveto.y+" z " + moveto.z);
mRenderer.updatemoveto(moveto.x, moveto.y);
}
prevx= curx;
prevy = cury;
mRenderer.updatecamera(x, y, z);
}
});
return true;
}
ClearRenderer mRenderer;
}
class ClearRenderer implements GLSurfaceView.Renderer {
GL10 mygl;
GL11 mygl11;
int viewport[] = new int[4];
float modelview[] = new float[16];
float projection[] = new float[16];
float wcoord[] = new float[4];
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // OpenGL docs.
gl.glShadeModel(GL10.GL_SMOOTH);// OpenGL docs.
gl.glClearDepthf(1.0f);// OpenGL docs.
gl.glEnable(GL10.GL_DEPTH_TEST);// OpenGL docs.
gl.glDepthFunc(GL10.GL_LEQUAL);// OpenGL docs.
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, // OpenGL docs.
GL10.GL_NICEST);
mygl = gl;
mygl11 = (GL11) gl;
int index;
int counter = 0;
float zcoord = -7.0f;
mygl11.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, modelview, 0);
mygl11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, projection, 0);
mygl11.glGetIntegerv(GL11.GL_VIEWPORT, viewport, 0);
for(int x=0;x<11;x++)
{
for(int y =0;y<10;y++)
{
index = tilemap1[y][x];
if(index==0)
{
tiles[counter]=new square(x,y,zcoord,0.5f,1.0f,0.0f,0f,"vert");
}
if(index==1)
{
tiles[counter]=new square(x,y,zcoord,0.5f,0f,1.0f,0f,"vert");
}
if(index==2)
{
tiles[counter]=new square(x,y,zcoord,0.5f,0.0f,0.0f,1f,"vert");
}
counter++;
}
}
}
public vector2d getworkcoords(float width,float height)
{
float[] depth = new float[1];
float winx = width;
float winy =viewport[3]-height;
//vector2d position = new vector2d(0,0);
int test = GLU.gluUnProject(winx, winy,0.0f, modelview, 0, projection,
0, viewport, 0, wcoord, 0);
vector2d v = new vector2d(0,0);
v.x = wcoord[0];
v.y = wcoord[1];
v.z = wcoord[2];
return v ;
}
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
gl.glMatrixMode(GL10.GL_PROJECTION);// OpenGL docs.
gl.glLoadIdentity();// OpenGL docs.
GLU.gluPerspective(gl, 45.0f,
(float) w / (float) h,
0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);// OpenGL docs.
gl.glLoadIdentity();// OpenGL docs.
}
public float movetox;
public float movetoy;
float currentposx;
float currentposy;
public void updatemoveto(float x , float y)
{
movetox = x;
movetoy = y;
}
public void onDrawFrame(GL10 gl) {
gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
currentposx = mycube.getcenterx();
currentposy = mycube.getcentery();
float x = movetox -currentposx;
float y = movetoy - currentposy;
double angle = Math.atan2(y, x);
double mx =.5f* Math.cos(angle);
double my = .5f* Math.sin(angle);
double mmx = mx+ currentposx;
double mmy = my+ currentposy;
mycube.updatecube((float)(mmx), (float)(mmy),0);
mycube.drawcube(gl);
for(int i = 0;i<110;i++)
{
tiles[i].draw(gl);
}
}
public void setColor(float r, float g, float b) {
mRed = r;
mGreen = g;
mBlue = b;
}
public void updatecamera(float myx, float myy, float myz)
{
mygl.glLoadIdentity();// OpenGL docs.
GLU.gluLookAt(mygl, myx, myy, myz, myx, myy, myz-10, 0, 1, 0);
}
private float mRed;
private float mGreen;
private float mBlue;
int tilemap1[][] = {
{0,0,0,0,0,0,0,0,0,0,0},
{0,1,2,1,1,1,1,1,1,1,0},
{0,1,2,1,1,1,1,1,1,1,0},
{0,1,2,1,1,1,1,1,1,1,0},
{0,1,2,2,2,1,1,1,1,1,0},
{0,1,1,1,2,1,1,1,1,1,0},
{0,1,1,1,2,1,1,1,1,1,0},
{0,1,1,1,2,1,1,1,1,1,0},
{0,1,1,1,2,2,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0},
};
square[] tiles = new square[110];
shapemaker mycube = new shapemaker(0,0,0,1);
}
I did not include the on create method and the on pause ones. I would also like advice on designing the code structure because my implementation is far from perfect.
So in short. I would like help figuring out how to modify the code I made to have a cube move to where i press. And how you would improve the code
Thanks
First of all,
you don't need to recreate vertices on every moving. It is very complex task and it will low the framerate (FPS). In you code you have model matrix. Usually it is responsible for translating, scaling rotating of your model(mesh, cube in your example). In common case you have to translate the model matrix and then multiple model, projection and view matrixes, you will get the matrix for your device screen. Then by multiplication of vertex postion and this matrix you'll get the right position of vertex.
you can look at this question/answer

Categories

Resources