I'm trying to display text in my OpenGL / JOGL app. Here is some of the code:
private void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
GLUgl2 glu = new GLUgl2();
float[] rgba = new float[4];
backgroundColor.getRGBComponents(rgba);
gl.glClearColor(rgba[0], rgba[1], rgba[2], 1);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
// Position the camera
glu.gluLookAt(cameraPos.x, cameraPos.y, cameraPos.z, cameraPos.x + cameraForward.x, cameraPos.y + cameraForward.y,
cameraPos.z + cameraForward.z, cameraUp.x, cameraUp.y, cameraUp.z);
gl.glPushMatrix();
GLUT glut = new GLUT();
gl.glTranslatef(0, 0, 0);
gl.glColor3f(1, 0, 0);
glut.glutBitmapString(GLUT.BITMAP_HELVETICA_18, "We're going to the moon!");
gl.glPopMatrix();
// ...
The text appears as soon as rendering begins, then runs off the right hand side of the screen. Why is this happening?
I'd like to display text in front of the user, not as a model in the world.
You need to set the current raster position before invoking glutBitmapString. The raster position is the pixel where the string will start being drawn. You can set it using the glRasterPos... family of functions. The reason your text seems to "run off" the right side of the screen is that calling glutBitmapString implicitly moves the raster position to the end of the string (see here).
There is very easy solution but it "links" your app against awt, which might be bad if you try to stay out of it in favour of newt.
Below example draws player osd using number of text renderers: one for play/pause glyph, one more for some information like time, etc., and yet another one for movie name.
import com.jogamp.opengl.util.awt.TextRenderer;
private static final Color DROP_SHADOW_COLOR = new Color(0, 0, 0, 0.5f);
class CustomRenderDelegate implements TextRenderer.RenderDelegate {
private int dropShadowDepth;
private Color color;
CustomRenderDelegate(int dropShadowDepth, Color color) {
this.dropShadowDepth = dropShadowDepth;
this.color = color;
}
public boolean intensityOnly() {
return false;
}
public Rectangle2D getBounds(CharSequence str, Font font, FontRenderContext frc) {
return getBounds(str.toString(), font, frc);
}
public Rectangle2D getBounds(String str, Font font, FontRenderContext frc) {
return getBounds(font.createGlyphVector(frc, str), frc);
}
public Rectangle2D getBounds(GlyphVector gv, FontRenderContext frc) {
Rectangle2D stringBounds = gv.getPixelBounds(frc, 0, 0);
return new Rectangle2D.Double(stringBounds.getX(), stringBounds.getY(), stringBounds.getWidth()
+ dropShadowDepth, stringBounds.getHeight() + dropShadowDepth);
}
public void drawGlyphVector(Graphics2D graphics, GlyphVector str, int x, int y) {
graphics.setColor(DROP_SHADOW_COLOR);
graphics.drawGlyphVector(str, x + dropShadowDepth, y + dropShadowDepth);
graphics.setColor(color);
graphics.drawGlyphVector(str, x, y);
}
public void draw(Graphics2D graphics, String str, int x, int y) {
graphics.setColor(DROP_SHADOW_COLOR);
graphics.drawString(str, x + dropShadowDepth, y + dropShadowDepth);
graphics.setColor(color);
graphics.drawString(str, x, y);
}
}
public void init(GLAutoDrawable drawable) {
...
pathRenderer = new TextRenderer(new Font("Helvetica", Font.ITALIC, 16), true, true, new CustomRenderDelegate(0,
Color.WHITE));
pathRenderer.setSmoothing(true);
playRenderer = new TextRenderer(new Font("Helvetica", Font.BOLD, 65), true, true, new CustomRenderDelegate(0,
Color.WHITE));
pauseRenderer = new TextRenderer(new Font("Helvetica", Font.BOLD, 50), true, true, new CustomRenderDelegate(0,
Color.WHITE));
osdRenderer = new TextRenderer(new Font("Helvetica", Font.PLAIN, 32), true, true, new CustomRenderDelegate(0,
Color.WHITE));
osdRenderer.setSmoothing(true);
}
private final void updateOsd() {
Time t = currentFrame != null ? currentFrame.getTime() : new Time(0, 0, 0, 0, 0);
String direction = video.direction == DirectionType.DIRECTION_LEFT ? "<" : ">";
String frameNumber = enterFrameNumber != null ? String.format("[%s]", enterFrameNumber)
: String.format("(%d)", t.fn);
osdText = String.format(" %s%s x %d # %.2f fps < %d/%d (%s) # %d fps", TimeUtil.hmsms(t.getPtsMillis()), frameNumber, (int) video.getPlaybackRate(), playbackFps, video.readyFrames(), maxFrames, direction, video.getFilterFps());
}
private void renderOsd(GLAutoDrawable drawable) {
updateOsd();
if (isOsdEnabled) {
maxModeWidth = (int) Math.max(maxModeWidth, playRenderer.getBounds("\u25B8").getWidth());
maxOsdHeight = (int) Math.max(maxOsdHeight, playRenderer.getBounds("\u25B8").getHeight());
if (isPaused) {
pauseRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
pauseRenderer.draw("\u2759", 10, drawable.getHeight() - maxOsdHeight - 2);
int barWidth = (int) pauseRenderer.getBounds("\u2759").getWidth();
pauseRenderer.draw("\u2759", 10 + barWidth - 3, drawable.getHeight() - maxOsdHeight - 2);
pauseRenderer.flush();
pauseRenderer.endRendering();
} else {
playRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
playRenderer.draw("\u25B8", 10, drawable.getHeight() - maxOsdHeight - 5);
playRenderer.flush();
playRenderer.endRendering();
}
int y = (int) ((maxOsdHeight + 10) - osdRenderer.getBounds(osdText).getHeight() / 2);
osdRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
osdRenderer.draw(osdText, maxModeWidth + 18, drawable.getHeight() - y - 2);
osdRenderer.flush();
osdRenderer.endRendering();
if (isFullScreen) {
pathRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
pathRenderer.draw(videoFile.getName(), 18, drawable.getHeight() - y - maxOsdHeight + 15);
pathRenderer.flush();
pathRenderer.endRendering();
}
}
}
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
renderFrame(drawable);
renderOsd(drawable);
gl.glFinish();
}
Related
I am currently learning jogl so I can make my own 2d game. All the textures for the tiles are stored in a single large tileset.
I tried to use Texture.getSubImageTexCoords() to draw a single tile, but the result was weird:
I'm not sure exactly how to describe it, but the upper left triangle that makes up the quad is stretching in a very strange way.
I want to display just a section of the tileset.
I tried looking for something online but couldn't find anything.
here is my code:
public class TestSubImage {
private GLU glu = new GLU();
private GLCanvas mainCanvas;
private Texture texture;
private TextureCoords tc;
class Listener implements GLEventListener {
public void init(GLAutoDrawable drawable) {
// Load texture
try {
texture = TextureIO.newTexture(TestSubImage.class.getResource("/images/sheet.png"), false, null);
texture.setTexParameteri(drawable.getGL(), drawable.getGL().GL_TEXTURE_MAG_FILTER, drawable.getGL().GL_NEAREST);
tc = texture.getSubImageTexCoords(0, 16, 16, 32); // sub texture coords
} catch (IOException e) {
e.printStackTrace();
}
// Set up
drawable.getGL().glClearColor(0.3f, 0.3f, 0.3f, 0);
glu = new GLU();
glu.gluOrtho2D(0, 512, 512, 0);
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
}
public void dispose(GLAutoDrawable drawable) {
}
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// where to draw the image
int x = 100;
int y = 100;
int width = 200;
int height = 200;
gl.glColor3f(1, 1, 1);
// Draw the image
texture.enable(gl);
texture.bind(gl);
gl.glBegin(GL2.GL_QUADS);
gl.glVertex2f(x, y);
gl.glTexCoord2f(tc.left(), tc.bottom());
gl.glVertex2f(x, y + height);
gl.glTexCoord2f(tc.right(), tc.bottom());
gl.glVertex2f(x + width, y + height);
gl.glTexCoord2f(tc.right(), tc.top());
gl.glVertex2f(x + width, y);
gl.glTexCoord2f(tc.left(), tc.top());
gl.glEnd();
texture.disable(gl);
}
}
private void run() {
// Create window
JFrame frame = new JFrame("Texture Coords Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create profile and capabilities
final GLProfile profile = GLProfile.get(GLProfile.GL2);
GLCapabilities caps = new GLCapabilities(profile);
// Now set up the main GLCanvas
mainCanvas = new GLCanvas(caps);
mainCanvas.addGLEventListener(new Listener());
frame.getContentPane().add(mainCanvas);
frame.setSize(512, 512);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String[] args) {
new TestSubImage().run();
}
}
The tileset is here.
glTexCoord2f sets the texcoord for the next vertex. So, you are rendering one vertex with the default texcoord (whatever that is), and then you are rendering each vertex with the previous vertex's texcoord. And the last texcoord call does nothing. (Well, it probably hangs around as the current texcoord and gets used for the first vertex on the next frame)
You need to call glTexCoord2f before glVertex2f.
P.S. It works the same for glColor3f/4f, glNormal3f, etc.
I don't use JOGL, but it looks like your
gl.glVertex2f(x, y);
gl.glTexCoord2f(tc.left(), tc.bottom());
gl.glVertex2f(x, y + height);
gl.glTexCoord2f(tc.right(), tc.bottom());
gl.glVertex2f(x + width, y + height);
gl.glTexCoord2f(tc.right(), tc.top());
gl.glVertex2f(x + width, y);
gl.glTexCoord2f(tc.left(), tc.top());
is incorrect. If we are pairing each glVertex2f with the line below it I would imagine it should look like
gl.glVertex2f(x, y);
gl.glTexCoord2f(tc.left(), tc.bottom());
gl.glVertex2f(x, y + height);
gl.glTexCoord2f(tc.left(), tc.top());
gl.glVertex2f(x + width, y + height);
gl.glTexCoord2f(tc.right(), tc.top());
gl.glVertex2f(x + width, y);
gl.glTexCoord2f(tc.right, tc.bottom());
Tell me how to make it change to the next one when you click on a picture. I use a library "ControlP5, cp5.addbutton" with a regular button in which I could do without a picture.
I have two examples, with a regular button and a picture, where I use a different way to change the picture by hovering the mouse and clicking in order to show you clearly.
"minutesss1" - a regular button with public void minutesss1() which uses .setCaptionLabel("ВЫКЛ").
"minutesss2" - How I think to use for the picture .setCaptionLabel("ВЫКЛ") / Not required ?????
Complete example code:
import controlP5.*;
ControlP5 cp5;
int min=0;
Button minutess1;
Button minutess2;
void setup() {
size(700,400);
PFont fontn = createFont("Times New Roman",18);
cp5 = new ControlP5(this);
PFont p = createFont("Times New Roman",18);
ControlFont font=new
ControlFont(p);
cp5.setFont(font);
minutess1 = cp5.addButton("minutesss1")
.setCaptionLabel("ВЫКЛ")
.setPosition(200,200)
.setSize(99,25);
PImage[] imgs1 = {loadImage("0.png"),loadImage("1.png"),loadImage("2.png")}; // ,loadImage("3.png"),loadImage("4.png"),loadImage("5.png"),loadImage("6.png")
minutess2 = cp5.addButton("minutesss2")
//.setCaptionLabel("ВЫКЛ")
.setPosition(400,200)
.setImages(imgs1);
minutess2.setSize(99,25);
textFont(fontn);}
public void minutesss1() {
min+=10;
if (min>60) {min=0; minutess1.setCaptionLabel("ВЫКЛ"); }
else minutess1.setCaptionLabel(str(min)+" Мин");}
void draw(){
background(0);
fill(255);}
It's great that you've posted the code formatted like that.
It would be even better if you format it in Processing (Ctrl + T) before to make it easier to read.
It is difficult to fully understand what your asking.
If you're using a translation tool you can try breaking long phrases into smaller, simpler sentences. Hopefully the translation tool will do a better job.
From what I can understand there are two questions here:
How can you call the same minutes updating function that works for the first button from the second button ?
How can you use custom images to skin the second button ?
The first question can be tackled multiple ways.
Here are a couple of options:
Option 1: Use controlEvent which gets called automatically when updating any controlP5 component. You can check which button was pressed and call a function accordingly:
import controlP5.*;
ControlP5 cp5;
int min=0;
Button minutess1;
Button minutess2;
void setup() {
size(700, 400);
PFont fontn = createFont("Times New Roman", 18);
cp5 = new ControlP5(this);
PFont p = createFont("Times New Roman", 18);
ControlFont font=new
ControlFont(p);
cp5.setFont(font);
minutess1 = cp5.addButton("minutesss1")
.setCaptionLabel("ВЫКЛ")
.setPosition(200, 200)
.setSize(99, 25);
//PImage[] imgs1 = {loadImage("0.png"), loadImage("1.png"), loadImage("2.png")}; // ,loadImage("3.png"),loadImage("4.png"),loadImage("5.png"),loadImage("6.png")
PImage[] imgs1 = {getImage(99,25,color(0,0,192)),
getImage(99,25,color(0,0,240)),
getImage(99,25,color(0,0,120))};
minutess2 = cp5.addButton("minutesss2")
//.setCaptionLabel("ВЫКЛ")
.setPosition(400, 200)
.setImages(imgs1);
minutess2.setSize(99, 25);
textFont(fontn);
}
PImage getImage(int w, int h, int c){
PImage img = createImage(w, h, RGB);
java.util.Arrays.fill(img.pixels, c);
img.updatePixels();
return img;
}
public void minutesss1() {
min+=10;
if (min>60) {
min=0;
minutess1.setCaptionLabel("ВЫКЛ");
} else minutess1.setCaptionLabel(str(min)+" Мин");
println(min,minutess1.getCaptionLabel().getText());
}
void draw() {
background(0);
fill(255);
}
public void controlEvent(ControlEvent event) {
if(event.controller() == minutess2){
minutesss1();
}
}
Option 2: Extract the instructions of the first button press function into a separate function that can be called by both. This is probably simpler and more intuitive to read:
import controlP5.*;
ControlP5 cp5;
int min=0;
Button minutess1;
Button minutess2;
void setup() {
size(700, 400);
PFont fontn = createFont("Times New Roman", 18);
cp5 = new ControlP5(this);
PFont p = createFont("Times New Roman", 18);
ControlFont font=new
ControlFont(p);
cp5.setFont(font);
minutess1 = cp5.addButton("minutesss1")
.setCaptionLabel("ВЫКЛ")
.setPosition(200, 200)
.setSize(99, 25);
//PImage[] imgs1 = {loadImage("0.png"), loadImage("1.png"), loadImage("2.png")}; // ,loadImage("3.png"),loadImage("4.png"),loadImage("5.png"),loadImage("6.png")
// don't have images to reproduce: making new ones
PImage[] imgs1 = {getImage(99,25,color(0,0,192)),
getImage(99,25,color(0,0,240)),
getImage(99,25,color(0,0,120))};
minutess2 = cp5.addButton("minutesss2")
//.setCaptionLabel("ВЫКЛ")
.setPosition(400, 200)
.setImages(imgs1);
minutess2.setSize(99, 25);
textFont(fontn);
}
PImage getImage(int w, int h, int c){
PImage img = createImage(w, h, RGB);
java.util.Arrays.fill(img.pixels, c);
img.updatePixels();
return img;
}
void updateMinutes(){
min+=10;
if (min>60) {
min=0;
minutess1.setCaptionLabel("ВЫКЛ");
} else minutess1.setCaptionLabel(str(min)+" Мин");
println(min,minutess1.getCaptionLabel().getText());
}
public void minutesss1() {
updateMinutes();
}
public void minutesss2() {
updateMinutes();
}
void draw() {
background(0);
fill(255);
}
Regarding the second part of your question it's unclear if you want to have images just for the default controlP5 states(default, over, active, highlight) using setImages() or not. If you pass more than 4 or less than 3 images they will be ignored as you can see in the source code
If you want to display a different image for each minutes update (e.g. off, 10 , 20, 30, 40, 50, 60) then you will need to make your own custom button.
The logic isn't that complicated and you can use the Button Example as a simpler starting point.
It would be great to encapsulate that more complex custom functionality and you'd need a few Object Oriented Programming (OOP) basics for that. You can check out the Objects tutorial and example
For illustration purposes here's a separate sketch that would display a different image for each of the button press states (ignoring the over/highlight states):
ImageButton button;
void setup(){
size(300, 300);
// button dimensions
int w = 75;
int h = 25;
// test with generated images
button = new ImageButton(112, 137, w, h,
new PImage[]{
// use loadImage with your own images instead of getImage :)
getImage(w, h, color(192, 0, 32 * 2)), // off
getImage(w, h, color(0, 0, 32 * 3)), // 10
getImage(w, h, color(0, 0, 32 * 4)), // 20
getImage(w, h, color(0, 0, 32 * 5)), // 30
getImage(w, h, color(0, 0, 32 * 6)), // 40
getImage(w, h, color(0, 0, 32 * 7)), // 50
getImage(w, h, color(0, 0, 32 * 8)), // 60
});
// loading images will be something similar to:
//button = new ImageButton(112, 137, w, h,
// new PImage[]{
// loadImage("0.png"), // off
// loadImage("1.png"), // 10
// loadImage("2.png"), // 20
// loadImage("3.png"), // 30
// loadImage("4.png"), // 40
// loadImage("5.png"), // 50
// loadImage("6.png"), // 60
// });
}
void draw(){
background(0);
button.draw();
}
void mousePressed(){
button.mousePressed(mouseX,mouseY);
println(button.min);
}
// test images to represent loaded state images
PImage getImage(int w, int h, int c){
PImage img = createImage(w, h, RGB);
java.util.Arrays.fill(img.pixels, c);
img.updatePixels();
return img;
}
// make a custom image button class
class ImageButton{
// minutes is the data it stores
int min = 0;
// images for each state
PImage[] stateImages;
// which image to display
int stateIndex;
// position
int x, y;
// dimensions: width , height
int w, h;
// text to display
String label = "ВЫКЛ";
ImageButton(int x, int y, int w, int h, PImage[] stateImages){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.stateImages = stateImages;
}
void mousePressed(int mx, int my){
// check the cursor is within the button bounds
boolean isOver = ((mx >= x && mx <= x + w) && // check horizontal
(my >= y && my <= y + h) ); // check vertical
if(isOver){
min += 10;
stateIndex++;
if (min>60) {
min = 0;
stateIndex = 0;
label = "ВЫКЛ";
} else {
label = min + " Мин";
}
}
}
void draw(){
// if the images and index are valid
if(stateImages != null && stateIndex < stateImages.length){
image(stateImages[stateIndex], x, y, w, h);
}else{
println("error displaying button state image");
println("stateImages: ");
printArray(stateImages);
println("stateIndex: " + stateIndex);
}
// display text
text(label, x + 5, y + h - 8);
}
}
Can someone help to make a static analogue clock in OpenGL 2.0 using Java? I used Bresenham Circle to draw a circle for the clock but is there any other way to draw a circle here? Then I drew an hour, minute, and second hand but I got an error in the render part while drawing the numbers. Can someone help me here with how to fix this? The code which I tried is following:
public class MyClock implements GLEventListener {
private int windowWidth = 1000;
private int windowHeight = 900;
public void display(GLAutoDrawable drawable) {
render(drawable);
}
//render
private void render(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glPointSize(5.0f);
//drawing circle
bresenhamCircle(new Point(100,100), 200, new Color(1, 0, 1), gl);
double x, y, d, delta_SE, delta_E;
x = 0;
double r = 200;
y = r;
d = 5-4*r;
setPixel(x ,y, gl);
setPixel(-x,y, gl);
setPixel(x,-y, gl);
setPixel(-x,-y, gl);
setPixel(y,x, gl);
setPixel(-y,x, gl);
setPixel(y,-x, gl);
setPixel(-y,-x, gl);
while (y>x) {
if (d >= 0) {
delta_SE = 4*(2*(x-y)+5);
d+=delta_SE; x++; y--;
}
else {
delta_E = 4*(2*x+3);
d+=delta_E; x++;
}
setPixel(x,y, gl);
setPixel(-x,y, gl);
setPixel(x,-y, gl);
setPixel(-x,-y, gl);
setPixel(y,x, gl);
setPixel(-y,x, gl);
setPixel(y,-x, gl);
setPixel(-y,-x, gl);
}
//hour hand
gl.glColor3d(0, 0, 1);
gl.glBegin(GL2.GL_LINES);
gl.glVertex2d(0, 00);
gl.glVertex2d(70, 70);
gl.glEnd();
//minute hand
gl.glColor3d(0, 0, 1);
gl.glBegin(GL2.GL_LINES);
gl.glVertex2d(0, 00);
gl.glVertex2d(150, 20);
gl.glEnd();
//seconds hand
gl.glColor3d(1, 0, 0);
gl.glBegin(GL2.GL_LINES);
gl.glVertex2d(0, 00);
gl.glVertex2d(120, -120);
gl.glEnd();
//drawing numbers
int AngleX, AngleY;
int radius;
double line;
for (int i=1;i<=12;i++) {
line = i/12*Math.PI*2;
radius=170;
AngleX=(int)((0)+(Math.sin(line)*radius));
AngleY=(int)((0)+(Math.cos(line)*radius));
gl.glColor3d(1, 1, 1);
String a= Integer.toString(i);
g.drawString(a,AngleX,AngleY);
}
}
//Bresenham Circle method
public void bresenhamCircle(Point center, double radius, Color color, GL2 gl) {
gl.glColor3d(0, 0, 1);
gl.glBegin(GL2.GL_POINTS);
gl.glVertex2d(00,200);
gl.glEnd();
}
private void setPixel(double x, double y,GL2 gl) {
gl.glColor3d(0.0, 1.0, 0.0);
gl.glBegin(GL2.GL_POINTS);
gl.glVertex2d(0,0);
gl.glVertex2d( x, y);
gl.glEnd();
}
public void dispose(GLAutoDrawable drawable) {
}
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glViewport(0, 0, windowWidth, windowHeight);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, 0, 1);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
gl.glEnable(GL2.GL_LINE_SMOOTH);
}
public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
GL2 gl = drawable.getGL().getGL2();
windowWidth = w;
windowHeight = h;
gl.glViewport(0, 0, w, h);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(-w / 2, w / 2, -h / 2, h / 2, 0, 1);
}
}
As far as I know, there isn't a simple method built into OpenGL ES 2.0 that draws text. That means you have to either find an open-source library that you can use, or you can create your own way of rendering text. This post outlines nicely the different ways that you can render text with OpenGL.
The best way I have found based on my research and which is also stated in the above link, is to render text through images. This tutorial shows how to create a basic text engine and is what I used to get an idea of how to render custom text. The idea is to take a texture atlas (a texture atlas is one image that contains all the letters, numbers, characters that you want to be able to render) and based on what string you want to draw, the engine will crop out the necessary letters, numbers, or characters from the atlas needed for your string and combine them into a square polygon that you can then render to the screen. The tutorial that I linked is a basic text engine, but once you understand how it works, you can then modify and improve it to your needs.
first of all, sorry, because of my rusty English. Since i learnt German i forgot the English.
I'm doing tests with libGDX and my code doesn't detect any collisions.
In my Screen:
public Pantalla(SpriteBatch batch_1) {
batch = batch_1;
screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight();
stage = new Stage(new StretchViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()),batch);
Gdx.input.setInputProcessor(stage);
camera = new OrthographicCamera();
camera.setToOrtho(false, 1000, 840);
camera.update();
mapas = new Mapas(camera);
// ACTORS
indiana_actor = new indiana_Actor();
//Here comes TOUCHPAD with Skin blaBlaBla...
if (touchpad.isTouched()) {
if (touchpad.getKnobX() > 120) {
indiana_actor.moveBy(32,0);
camera.translate(32, 0);
return; }
}
stage.addActor(indiana_actor);
stage.addActor(touchpad);
Gdx.input.setInputProcessor(stage);
}
public void render(float delta) {//TODO RENDER
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
mapas.MapasRender(camera,indiana_actor);
batch.begin();
batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
indiana_actor Class:
public indiana_Actor() {
W=Gdx.graphics.getWidth(); H=Gdx.graphics.getHeight();
bounds=new Rectangle((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight());
}
Animation anim_temp;
#Override
public void draw(Batch batch, float parentAlpha) {
stateTime += Gdx.graphics.getDeltaTime();
batch.setColor(getColor());
batch.draw(Assets.indiana_stop_arriba, (W/2), (H/2), 110, 160);
bounds=new Rectangle((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight());
}
and Mapas Class.
In these class i get the Objects in the "objetos" TiledLayer, and triying to check collisions with a for(...) in the renderer.
public Mapas(OrthographicCamera camera2){
map = new TmxMapLoader().load("terrain/prueba.tmx");
renderer = new OrthogonalTiledMapRenderer(map, 10);//ESCALA
renderer.setView(camera2);
collisionObjects = map.getLayers().get("objetos").getObjects();
collisionRects = new Array<Rectangle>();
collisionRects_total=collisionObjects.getCount();
int tileWidth = 32; // whatever your tile width is
int tileHeight = 32; // whatever your tile height is
for (int i = 0; i < collisionObjects.getCount(); i++) {
RectangleMapObject obj = (RectangleMapObject) collisionObjects.get(i);
Rectangle rect = obj.getRectangle();
collisionRects.add(new Rectangle(rect.x / tileWidth, rect.y / tileHeight, rect.width / tileWidth, rect.height / tileHeight));
}
}
public void MapasRender(OrthographicCamera camera2,indiana_Actor indi){
camera2.update();
renderer.setView(camera2);
renderer.render();
for (int i = 0; i < collisionRects_total; i++) {
Rectangle rect = collisionRects.get(i);
if (indi.bounds.overlaps(rect)){
Gdx.app.log("EVENTO", "MAPAS RENDER - COLISION!");
}if (rect.overlaps(indi.bounds)){
Gdx.app.log("EVENTO", "MAPAS RENDER - COLISION!");
}
}
}
I know (Through the logcat) that the
" for (int i = 0; i < collisionRects_total; i++) {
Rectangle rect = collisionRects.get(i); "
get always the objectsRectangle , but in the next line find any overlaps.
Is that a problem with the actor bounds-rectangle?A problem when moving actor through the map??....
Thanks in advance!!
Why dont U at first check if your rectangle for collision draw correctly on position. You can do that by calling
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.setColor(Color.NAVY);
shapeRenderer.rect(object.getrect().x,
object.getrect().y,object.getrect().width,
object.getrect().height);
may be you draw collision rectangles at wrong position so collision will never occur.
I'm currently trying to make a game, and I'm still novice with using cameras, and I'm thinking that two OrthographicCameras may be necessary, but I'm not sure if that's the most efficient way, or even how to do so.
Basically, I want this to be the layout for it:
The Main Area is where the main stuff is, which is a Server Interface. The Game Level is where the actual game part is in. I am currently using a ScissorStack to cut the region, but with this demo, results make me question how to do this:
public class TestScissorStackAndCamera extends ApplicationAdapter {
private SpriteBatch batch;
private OrthographicCamera camera;
private Sprite sprite;
private int width, height;
#Override
public void create() {
Gdx.gl.glClearColor(0, 0, 0, 0);
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
batch = new SpriteBatch();
camera = new OrthographicCamera(width, height);
camera.position.set(width / 2, height / 2, 0);
camera.update();
createSprite();
}
private void createSprite() {
Pixmap map = new Pixmap(width, height, Format.RGBA8888);
map.setColor(Color.RED);
map.fillRectangle(0, 0, width, height);
map.setColor(Color.BLUE);
map.drawLine(width / 2, 0, width / 2, height);
map.drawLine(0, height / 2, width, height / 2);
Texture texture = new Texture(map);
sprite = new Sprite(texture);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined); // The Question!
batch.begin();
{
Rectangle scissors = new Rectangle();
Rectangle area = new Rectangle(10, 10, width - 20, height - 20);
ScissorStack.calculateScissors(camera, batch.getTransformMatrix(), area, scissors);
ScissorStack.pushScissors(scissors);
batch.draw(sprite, 0, 0);
batch.flush();
ScissorStack.popScissors();
}
batch.end();
}
public static void main(String[] args) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.title = "ScissorStack & Camera Test";
config.resizable = false;
new LwjglApplication(new TestScissorStackAndCamera(), config);
}
}
Questioning batch.setProjectionMatrix(camera.combined)
I marked a line in the code with a comment, The Question!, which is what is affecting the results. If I don't have it, using the camera.translate(...) method, the image is drawn at (0, 0) but what it does is it moves what part is viewed. If I do have that line, when I use the camera.translate(...) method, the image is drawn respectively to the position of the camera.
In respect to the game that I'm currently developing, it behaves awkwardly without the projectionMatrix not being set, but when I do set it, it messes up the positioning of the rest of the game. I even added some testing features, and it's not rendering inside of the correct ScissorStack
How could I go about setting up two cameras, or what could I do to set up what I'm trying to correctly and efficiently?
With my actual game (not the mock-up) this is what it is doing. It should be rendering inside of the red lines, but it's not:
If you'd like to see my current code for my GameLevel that is handling the ScissorStack and OrthographicCamera:
public GameLevel(int x, int y, int displayWidth, int displayHeight) {
this.x = x; // x = 10
this.y = y; // y = 10
this.displayWidth = displayWidth; // displayWidth = Gdx.graphics.getWidth() - x - 10
this.displayHeight = displayHeight; // displayHeight = Gdx.graphics.getHeight() - y - 120
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(displayWidth / 2, displayHeight / 2, 0);
// FBLAGame.batch.setProjectionMatrix(camera.combined);
camera.update();
init();
}
...
#Override
public void render() {
Rectangle area = new Rectangle(x, y, displayWidth, displayHeight);
Rectangle scissor = new Rectangle();
Matrix4 matrix = FBLAGame.batch.getTransformMatrix();
ScissorStack.calculateScissors(camera, matrix, area, scissor);
ScissorStack.pushScissors(scissor);
renderLevel();
FBLAGame.batch.flush();
ScissorStack.popScissors();
Pixmap map = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Format.RGBA8888);
map.setColor(Color.RED);
map.drawRectangle((int) area.x, (int) area.y, (int) area.width, (int) area.height);
Texture t = new Texture(map);
map.dispose();
FBLAGame.batch.draw(t, 0, 0);
}