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?
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);
}
}
}
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