Making a randomly moving clickable button on Android - java

I'm looking to create randomly moving clickable buttons in Android (for a childrens game).
I followed the code on this website to create some randomly moving circles around the screen
http://www.techrepublic.com/blog/software-engineer/bouncing-a-ball-on-androids-canvas/
with the Animated words view changed to this:
public class AnimatedWordsView extends ImageView {
private Context myContext;
int [] xCoOrd = {-1, -2, -3, -4, -5, -6, -7, -8};
int [] yCoOrd = {-1, -2, -3, -4, -5, -6, -7, -8};
int [] xVeloc = {4, 8, 12, 16, 20, 20, 20, 20};
int [] yVeloc = {2, 4, 6, 8, 10, 12, 14, 16};
private Handler handler;
private final int FRAME_RATE = 30;
public AnimatedWordsView(Context context, AttributeSet attributes){
super(context, attributes);
myContext = context;
handler = new Handler();
}
private Runnable run = new Runnable() {
#Override
public void run() {
invalidate();
}
};
protected void onDraw(Canvas canvas){
BitmapDrawable [] word = {(BitmapDrawable) myContext.getResources().getDrawable(R.drawable.word_bubble_blue), (BitmapDrawable) myContext.getResources().getDrawable(R.drawable.word_bubble_green),
(BitmapDrawable) myContext.getResources().getDrawable(R.drawable.word_bubble_red), (BitmapDrawable) myContext.getResources().getDrawable(R.drawable.word_bubble_yellow),
(BitmapDrawable) myContext.getResources().getDrawable(R.drawable.word_bubble_green), (BitmapDrawable) myContext.getResources().getDrawable(R.drawable.word_bubble_blue),
(BitmapDrawable) myContext.getResources().getDrawable(R.drawable.word_bubble_red), (BitmapDrawable) myContext.getResources().getDrawable(R.drawable.word_bubble_yellow)};
for(int count = 0; count <=7; count++ ) {
if (xCoOrd[count] < 0 && yCoOrd[count] < 0) {
xCoOrd[count] = this.getWidth() / 2;
yCoOrd[count] = this.getHeight() / 2;
} else {
xCoOrd[count] += xVeloc[count];
yCoOrd[count] += yVeloc[count];
}
if ((xCoOrd[count] > this.getWidth() - word[count].getBitmap().getWidth()) || (xCoOrd[count] < 0)) {
xVeloc[count] = xVeloc[count] * -1;
}
if ((yCoOrd[count] > this.getHeight() - word[count].getBitmap().getHeight()) || (yCoOrd[count] < 0)) {
yVeloc[count] = yVeloc[count] * -1;
}
canvas.drawBitmap(word[count].getBitmap(),xCoOrd[count],yCoOrd[count],null);
}
handler.postDelayed(run, FRAME_RATE);
}
What i'm looking for is something that does something similar to what this does, but allows me to add text to the circles and make them clickable
Is there any way to do this?
Thanks

You can use drawText method for Canvas to draw text:
public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)
Something like this:
Paint paint = new Paint();
canvas.drawPaint(paint);
paint.setColor(Color.MY_COLOR);
paint.setTextSize(24);
canvas.drawText("My Text", x, y, paint);
To click the view you just need to add a onClickListener to it:
myAnimatedWordsView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});

Related

Full game grid not outputting in Android Studios? [duplicate]

I am currently making an android app which plays the puzzle game hashi. I am currently struggling to output the game grid. i want to output a 2d array like bellow-
1 0 0 0 1
0 2 0 0 2
2 0 3 0 1
0 0 0 0 0
0 0 2 0 2
however when i run the application in the emulator it outputs just a blank white screen.
main activity-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new boardView(this));
//sets the view to the board view to show the puzzle on open.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
game board class-
public class boardView extends View {
public float IslandX;
public float IslandY;
public int islandDiameter;
private Canvas canvas;
public boardView(Context context) {
super(context);
}
int gameBoard[][] = {{0, 1, 0, 0, 1}, {0, 2, 0, 0, 2}, {2, 0, 3, 0, 1}, {0, 0, 0, 0, 0}, {0, 0, 2, 0, 2}};
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void DrawBoard(Canvas canvas){
Paint Island = new Paint();
Island.setStyle(Paint.Style.FILL);
Island.setStyle(Paint.Style.FILL);
float stepX = canvas.getWidth() / 5.f;
float stepY = canvas.getHeight() / 5.f;
for (int i = 0; i < 5; i++) {
for (int R = 0; R < 5; R++) {
IslandX = i * stepX;
IslandY = R * stepY;
if (gameBoard[i][R] == 0) {
Island.setColor(Color.BLUE);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
} else if (gameBoard[i][R] == 1) {
Island.setColor(Color.BLACK);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
} else if (gameBoard[i][R] == 2) {
Island.setColor(Color.BLUE);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
}
}
}
}
}
To make your board visible, you have to move your code from Drawboard to the overwritten method onDraw and in the onCreate method, you have to call invalidate() on an instance of the class boardView, that calls the onDraw method to update the screen, if visible.

Game grid not outputting in Android Studios?

I am currently making an android app which plays the puzzle game hashi. I am currently struggling to output the game grid. i want to output a 2d array like bellow-
1 0 0 0 1
0 2 0 0 2
2 0 3 0 1
0 0 0 0 0
0 0 2 0 2
however when i run the application in the emulator it outputs just a blank white screen.
main activity-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new boardView(this));
//sets the view to the board view to show the puzzle on open.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
game board class-
public class boardView extends View {
public float IslandX;
public float IslandY;
public int islandDiameter;
private Canvas canvas;
public boardView(Context context) {
super(context);
}
int gameBoard[][] = {{0, 1, 0, 0, 1}, {0, 2, 0, 0, 2}, {2, 0, 3, 0, 1}, {0, 0, 0, 0, 0}, {0, 0, 2, 0, 2}};
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void DrawBoard(Canvas canvas){
Paint Island = new Paint();
Island.setStyle(Paint.Style.FILL);
Island.setStyle(Paint.Style.FILL);
float stepX = canvas.getWidth() / 5.f;
float stepY = canvas.getHeight() / 5.f;
for (int i = 0; i < 5; i++) {
for (int R = 0; R < 5; R++) {
IslandX = i * stepX;
IslandY = R * stepY;
if (gameBoard[i][R] == 0) {
Island.setColor(Color.BLUE);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
} else if (gameBoard[i][R] == 1) {
Island.setColor(Color.BLACK);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
} else if (gameBoard[i][R] == 2) {
Island.setColor(Color.BLUE);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
}
}
}
}
}
To make your board visible, you have to move your code from Drawboard to the overwritten method onDraw and in the onCreate method, you have to call invalidate() on an instance of the class boardView, that calls the onDraw method to update the screen, if visible.

How to output ovals from a 2d array in Android Studios? [duplicate]

I am currently making an android app which plays the puzzle game hashi. I am currently struggling to output the game grid. i want to output a 2d array like bellow-
1 0 0 0 1
0 2 0 0 2
2 0 3 0 1
0 0 0 0 0
0 0 2 0 2
however when i run the application in the emulator it outputs just a blank white screen.
main activity-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new boardView(this));
//sets the view to the board view to show the puzzle on open.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
game board class-
public class boardView extends View {
public float IslandX;
public float IslandY;
public int islandDiameter;
private Canvas canvas;
public boardView(Context context) {
super(context);
}
int gameBoard[][] = {{0, 1, 0, 0, 1}, {0, 2, 0, 0, 2}, {2, 0, 3, 0, 1}, {0, 0, 0, 0, 0}, {0, 0, 2, 0, 2}};
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void DrawBoard(Canvas canvas){
Paint Island = new Paint();
Island.setStyle(Paint.Style.FILL);
Island.setStyle(Paint.Style.FILL);
float stepX = canvas.getWidth() / 5.f;
float stepY = canvas.getHeight() / 5.f;
for (int i = 0; i < 5; i++) {
for (int R = 0; R < 5; R++) {
IslandX = i * stepX;
IslandY = R * stepY;
if (gameBoard[i][R] == 0) {
Island.setColor(Color.BLUE);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
} else if (gameBoard[i][R] == 1) {
Island.setColor(Color.BLACK);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
} else if (gameBoard[i][R] == 2) {
Island.setColor(Color.BLUE);
canvas.drawOval(IslandX, IslandY, 50, 50, Island);
}
}
}
}
}
To make your board visible, you have to move your code from Drawboard to the overwritten method onDraw and in the onCreate method, you have to call invalidate() on an instance of the class boardView, that calls the onDraw method to update the screen, if visible.

Moving counters along a 2d array

I have three classes and am trying to make a game whereby users move along a grid depending on what is rolled by a die.
I have my main BoardGame class, containing the GUI and the counters which currently are Jlabel images (i'm open to suggestions as to what I could use instead of a JLabel - i wasnt so sure myself). I have a Grid class which I have arranged into a 2D array and called an instance of in the BoardGame class, and I have a die class which rolls a random number from 1-6.
I am trying to get me counters to start at the first square on the grid, and then advance in a left-to-right-right-to-left fashion. I am unsure however of how to make the counters move through the grid in the first place. Hopefully, if I can figure this out, I believe I can then implement them moving a specific amount via the die.
Thanks for the help in advance
GameBoard class:
public class GameBoard extends javax.swing.JFrame {
private JLabel Board;
private JLabel GreenDot;
private JLabel redDot;
private JButton startButton;
private Grid grid;
private Die die;
/**
* Auto-generated main method to display this JFrame
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Grid grid = new Grid();
GameBoard inst = new GameBoard(grid);
inst.setLocationRelativeTo(null);
inst.setVisible(true);
}
});
}
public GameBoard(Grid grid) {
super();
this.grid = grid;
initGUI();
}
private void initGUI() {
try {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(null);
{
redDot = new JLabel();
getContentPane().add(redDot);
redDot.setText("jLabel1");
redDot.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/download.png")));
redDot.setBounds(220, 434, 20, 12);
redDot.setBorder(new LineBorder(new java.awt.Color(0,0,0), 1, false));
}
{
GreenDot = new JLabel();
getContentPane().add(GreenDot);
GreenDot.setText("jLabel1");
GreenDot.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/3d-green-ball-th.png")));
GreenDot.setBounds(222, 453, 21, 13);
GreenDot.setBorder(new LineBorder(new java.awt.Color(0,0,0), 1, false));
}
{
startButton = new JButton();
getContentPane().add(startButton);
startButton.setText("Start Game");
startButton.setBounds(64, 443, 83, 23);
}
{
Board = new JLabel();
getContentPane().add(Board);
Board.setLayout(null);
Board.setText("jLabel1");
Board.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/board.jpg")));
Board.setBounds(204, -1, 742, 484);
}
pack();
this.setSize(963, 523);
} catch (Exception e) {
//add your error handling code here
e.printStackTrace();
}
}
}
Grid class:
public class Grid {
int[][] multi = {
{ 0, 0,-1, 0, 0,-1, 0,-1, 0, 0},
{ 0, 0, 0, 0, 0, 0,-1, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{ 0,-1, 0,-1, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0,-1, 0, 0, 1},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0},
{ 0, 0, 0,-1, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0}
};
}
Die class:
public class Die {
public Die() {
}
public void dieRoll() {
int SIDES = 6;
int roll = (int) (Math.random() * SIDES) + 1;
System.out.println(roll);
}
}
A simple way of doing this would be to change the die class so it has
{
private int sides;
public Die(int numSides){
sides = numSides;
}
public int roll(){
return (int) (Math.random() * SIDES) + 1
}
}
Then you can roll a six sided die like so
//this creates the die
Die sixSides = new Die(6);
//this rolls the die and prints the roll
System.out.print("That roll got you a " + sixSides.roll());
to move along a 2D array, all you need to do is use the modulus and you need to create a point object class
public position move(int num, int x, int y){//input is dice roll int then current position
for(int i = 0; i < num;i++){
if(i%10==0){
y++;
x = 0;
}else{
x++;
}
}
return new point(x,y);
}
To access the x and y positions of the point object you would need to write get and set methods for the object.
something like this
point player1 = new point(0,0);
int xposition = player1.getX

Best way to boost the performance of my LWJGL game?

I am putting together a small project for school that involves rendering the periodic table. I chose to use LWJGL to do this. The problem is, however, that when I render the table, the game starts out at ~30fps(capped at 60fps), and quickly fluctuates to a single-digit fps. I believe that the problem could be a memory leak, but I am unsure. Can anybody see any glaring problems with my code? Here are the main classes involved in rendering the table:
EntityPeriodicTable: In charge of holding a huge array of EntityElement objects(see below), activating their logic(tick() and updateInput()).
package com.flafla2.periodicTable;
import org.lwjgl.opengl.GL11;
public class EntityPeriodicTable extends ClickableEntity { //ClickableEntity is an abstract class in charge of the tick(), updateInput(), and render() methods, as well as positioning
public EntityElement[] elements = {//This is unfinished, but you get the idea.
//new EntityElement(Atomic #, State, Metal, "Symbol", "Name", new Vector2D(posx,posy), this)
new EntityElement(1, 2, 2, "H", "Hydrogen", new Vector2D(1,1), this),
new EntityElement(2, 2, 2, "He", "Helium", new Vector2D(18,1), this),
new EntityElement(3, 0, 0, "Li", "Lithium", new Vector2D(1,2), this),
new EntityElement(4, 0, 0, "Be", "Beryllium", new Vector2D(2,2), this),
new EntityElement(5, 0, 1, "B", "Boron", new Vector2D(13,2), this),
new EntityElement(6, 0, 2, "C", "Carbon", new Vector2D(14,2), this),
new EntityElement(7, 2, 2, "N", "Nitrogen", new Vector2D(15,2), this),
new EntityElement(8, 2, 2, "O", "Oxygen", new Vector2D(16,2), this),
new EntityElement(9, 2, 2, "F", "Fluorine", new Vector2D(17,2), this),
new EntityElement(10,2, 2, "Ne", "Neon", new Vector2D(18,2), this),
new EntityElement(11, 0, 0, "Na", "Sodium", new Vector2D(1,3), this),
new EntityElement(12, 0, 0, "Mg", "Magnesium", new Vector2D(2,3), this),
new EntityElement(13, 0, 0, "Al", "Aluminum", new Vector2D(13,3), this),
new EntityElement(14, 0, 1, "Si", "Silicon", new Vector2D(14,3), this),
new EntityElement(15, 0, 2, "P", "Phosphorous", new Vector2D(15,3), this),
new EntityElement(16, 0, 2, "S", "Sulfur", new Vector2D(16,3), this),
new EntityElement(17, 2, 2, "Cl", "Chlorine", new Vector2D(17,3), this),
new EntityElement(18, 2, 2, "Ar", "Argon", new Vector2D(18,3), this),
new EntityElement(19, 0, 0, "K", "Potassium", new Vector2D(1,4), this),
new EntityElement(20, 0, 0, "Ca", "Calcium", new Vector2D(2,4), this),
new EntityElement(21, 0, 0, "Sc", "Scandium", new Vector2D(3,4), this),
new EntityElement(22, 0, 0, "Ti", "Hydrogen", new Vector2D(4,4), this),
new EntityElement(23, 0, 0, "V", "Hydrogen", new Vector2D(5,4), this),
new EntityElement(24, 0, 0, "Cr", "Hydrogen", new Vector2D(6,4), this),
new EntityElement(25, 0, 0, "Mn", "Hydrogen", new Vector2D(7,4), this),
new EntityElement(26, 0, 0, "Fe", "Hydrogen", new Vector2D(8,4), this),
new EntityElement(27, 0, 0, "Co", "Hydrogen", new Vector2D(9,4), this),
new EntityElement(28, 0, 0, "Ni", "Hydrogen", new Vector2D(10,4), this),
new EntityElement(29, 0, 0, "Cu", "Hydrogen", new Vector2D(11,4), this),
new EntityElement(30, 0, 0, "Zn", "Hydrogen", new Vector2D(12,4), this),
new EntityElement(31, 0, 0, "Ga", "Hydrogen", new Vector2D(13,4), this),
new EntityElement(32, 0, 1, "Ge", "Hydrogen", new Vector2D(14,4), this),
new EntityElement(33, 0, 1, "As", "Hydrogen", new Vector2D(15,4), this),
new EntityElement(34, 0, 2, "Se", "Hydrogen", new Vector2D(16,4), this),
new EntityElement(35, 1, 2, "Br", "Hydrogen", new Vector2D(17,4), this),
new EntityElement(36, 2, 2, "Kr", "Hydrogen", new Vector2D(18,4), this),
};
public final int ELEMENT_SIZE = 40;
public Vector2D mousePos = new Vector2D(0,0); //Simple 2D vector struct.
public double[] SOLID_RGB = {0,0,0};
public double[] LIQUID_RGB = {0,0,1};
public double[] GAS_RGB = {1,0,0};
public double[] METAL_RGB;
public double[] NONMETAL_RGB;
public double[] METALLOID_RGB;
public double[] RECENT_RGB;
public EntityPeriodicTable(Vector2D pos) {
this.pos = pos;
METAL_RGB = new double[3];
METAL_RGB[0] = 0.596078431; //152/255
METAL_RGB[1] = 0.984313725; //251/255
METAL_RGB[2] = 0.596078431; //152/255
NONMETAL_RGB = new double[3];
NONMETAL_RGB[0] = 1;
NONMETAL_RGB[1] = 0.647058824; //165/255
NONMETAL_RGB[2] = 0;
METALLOID_RGB = new double[3];
METALLOID_RGB[0] = 0.866666667; //221/255
METALLOID_RGB[1] = 0.62745098; //160/255
METALLOID_RGB[2] = 0.866666667; //221/255
RECENT_RGB = new double[3];
RECENT_RGB[0] = 0.803921569; //205/255
RECENT_RGB[1] = 0.788235294; //201/255
RECENT_RGB[2] = 0.788235294; //201/255
}
#Override
void render() {
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
for(int x=0;x<elements.length;x++)
elements[x].render();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
for(int x=0;x<elements.length;x++)
elements[x].renderWithTex();
}
#Override
void tick() {
for(int x=0;x<elements.length;x++)
elements[x].tick();
}
#Override
public void updateInput(Vector2D mousePos)
{
this.mousePos = mousePos;
for(int x=0;x<elements.length;x++)
{
if(mousePos.isInBoundsWithDim(elements[x].pos.x, elements[x].pos.y, elements[x].dim.x, elements[x].dim.y))
elements[x].isSelected = true;
else
elements[x].isSelected = false;
}
}
#Override
void onEntityClicked() {
for(int x=0;x<elements.length;x++)
{
if(mousePos.isInBoundsWithDim(elements[x].pos.x, elements[x].pos.y, elements[x].dim.x, elements[x].dim.y))
elements[x].onEntityClicked();
}
}
}
EntityElement: Holds data of a specific element on the table, and renders it(render code is unfinished)
package com.flafla2.periodicTable;
import org.lwjgl.opengl.GL11;
public class EntityElement extends ClickableEntity {
String symbol;
String element;
int atomicNumber;
EntityPeriodicTable table;
int state;//0=solid, 1=liquid, 2=gas
int metalState;//0=metal, 1=metalloid, 2=nonmetal, 3=discovered recently
Vector2D gridPos;
public EntityElement(int an, int st, int ms, String sy, String en, Vector2D gp, EntityPeriodicTable pt)
{
symbol = sy;
element = en;
atomicNumber = an;
table = pt;
state = st;
metalState = ms;
gridPos = gp;
dim.x = table.ELEMENT_SIZE; dim.y = table.ELEMENT_SIZE;
pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1); pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1);
}
public double[] getStateColor()
{
switch(state)
{
case 0:
return table.SOLID_RGB;
case 1:
return table.LIQUID_RGB;
case 2:
return table.GAS_RGB;
default:
double[] d = {0.0d,0.0d,0.0d};
return d;
}
}
public double[] getMetalColor()
{
switch(metalState)
{
case 0:
return table.METAL_RGB;
case 1:
return table.METALLOID_RGB;
case 2:
return table.NONMETAL_RGB;
case 3:
return table.RECENT_RGB;
default:
double[] d = {0.0d,0.0d,0.0d};
return d;
}
}
#Override
void render() {
GL11.glPushMatrix();
GL11.glTranslatef(pos.x, pos.y, 0);
double[] d = getMetalColor();
GL11.glColor3d(d[0], d[1], d[2]);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glVertex2f(0, 0);//topleft
GL11.glVertex2f(dim.x, 0);//topright
GL11.glVertex2f(dim.x, dim.y);//bottomright
GL11.glVertex2f(0, dim.y);//bottomleft
}
GL11.glEnd();
GL11.glColor3d(1.0d, 1.0d, 1.0d);
GL11.glPopMatrix();
}
public void renderWithTex()
{
Font.drawString(symbol, new Vector2D(pos.x+dim.x/2-Font.getStringWidth(symbol,2)/2,pos.y+dim.y/2-Font.FONT_HEIGHT), 2);
}
#Override
void tick() {
if(isSelected)
{
dim.x = table.ELEMENT_SIZE+6; dim.y = table.ELEMENT_SIZE+6;
pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1)-3; pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1)-3;
} else
{
dim.x = table.ELEMENT_SIZE; dim.y = table.ELEMENT_SIZE;
pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1); pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1);
}
}
#Override
void onEntityClicked() {
}
}
Font: Handles rendering text onscreen:
package com.flafla2.periodicTable;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import org.lwjgl.opengl.GL11;
public class Font {
public static final String fontText = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:;?!\"&',-.[]#()+ ";
public static final BufferedImage fontSheet = TextureLoader.loadTexture("/res/text.png");
public static final int FONT_WIDTH = 9;
public static final int FONT_HEIGHT = 8;
public static void drawString(String s, Vector2D pos, float dim)
{
drawString(s,pos,new Vector2D((int)Math.floor(dim*FONT_WIDTH),(int)Math.floor(dim*FONT_HEIGHT)));
}
public static void drawString(String s, Vector2D pos)
{
drawString(s,pos,new Vector2D(9,8));
}
public static void drawString(String s, Vector2D pos, Vector2D dim)
{
for(int x=0;x<s.length();x++)
{
drawLetter(s.charAt(x),new Vector2D(pos.x+dim.x*x,pos.y),dim);
}
}
public static int getStringWidth(String s)
{
return s.length()*FONT_WIDTH;
}
public static int getStringWidth(String s,float f)
{
return (int)Math.floor(s.length()*FONT_WIDTH*f);
}
public static Vector2D getPosOfLetterOnImg(Character c,int gridNumb)
{
int xOffset = 0;
int yOffset = 0;
if(!c.equals(' '))
{
int letterNumb = fontText.indexOf(c);
xOffset = (letterNumb%26)*FONT_WIDTH;
if(xOffset != 0)
xOffset -=1;
yOffset = 0;
int yGridOffset = (letterNumb < 26) ? 0 : ((letterNumb < 52) ? 1 : 2);
switch(gridNumb)
{
case 1:
yOffset = 34;
break;
case 2:
yOffset = 69;
break;
default:
yOffset = 0;
}
for(int x=0;x<yGridOffset;x++)
yOffset += FONT_HEIGHT+x+3;
} else
{
xOffset = 235;
yOffset = 92;
}
return new Vector2D(xOffset,yOffset);
}
public static void drawLetter(Character c, Vector2D pos, Vector2D dim)
{
if(fontSheet == null)
return;
Vector2D letterPos = getPosOfLetterOnImg(c,2);
BufferedImage letterImage = fontSheet.getSubimage(letterPos.x, letterPos.y, FONT_WIDTH, FONT_HEIGHT);
int textureID = TextureLoader.loadGLTexture(letterImage);
letterImage = null;
GL11.glPushMatrix();
GL11.glTranslatef(pos.x, pos.y, 0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(dim.x, 0);
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(dim.x, dim.y);
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(0, dim.y);
}
GL11.glEnd();
GL11.glPopMatrix();
}
}
TextureLoader: Loads textures(duh lol)
package com.flafla2.periodicTable;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
public class TextureLoader {
public static BufferedImage loadTexture(String texturePath)
{
try {
return ImageIO.read(PeriodicTable.class.getResource(texturePath));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private static final int BYTES_PER_PIXEL = 4;
public static int loadGLTexture(BufferedImage image){
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * BYTES_PER_PIXEL); //4 for RGBA, 3 for RGB
for(int y = 0; y < image.getHeight(); y++){
for(int x = 0; x < image.getWidth(); x++){
int pixel = pixels[y * image.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component
buffer.put((byte) (pixel & 0xFF)); // Blue component
buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA
}
}
buffer.flip(); //FOR THE LOVE OF GOD DO NOT FORGET THIS
// You now have a ByteBuffer filled with the color data of each pixel.
// Now just create a texture ID and bind it. Then you can load it using
// whatever OpenGL method you want, for example:
int textureID = GL11.glGenTextures(); //Generate texture ID
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); //Bind texture ID
//Setup wrap mode
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
//Setup texture scaling filtering
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
//Send texel data to OpenGL
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
buffer = null;
//Return the texture ID so we can bind it later again
return textureID;
}
}
I know, it's a lot of code, but if anyone can help me out it would be greatly appreciated.
Thanks, Flafla2.
Thought you allready solved it there is more room for improvement. I see you have your font in an image and for each character you want to draw you get the part of the image with that letter load it into a texture and afterwards all that needs to be cleaned up.
Better to load the whole image into one big texture, keep that texture for the duration of your program and reuse it when rendering each frame. You can select the right characters to render by specifying the right texture coordinates.
You should be able to hit your 60fps cap with low cpu usage unless your MacBook is really old.
Alright, I found the problem.
In TextureLoader.java, I didn't use glDeleteTextures(textureID), so the textures used in Font.java weren't being unloaded from memory. Now, I am getting a stable 50+ fps(on my crappy macbook, of course).
Also, the other checked answer boosted my fps to ~60. In case anyone is wondering, here is the new drawLetter() method, with changes:
public static void drawLetter(Character c, Vector2D pos, Vector2D dim)
{
if(fontSheet == null)
return;
Vector2D letterPos = getPosOfLetterOnImg(c,2);
//BufferedImage letterImage = fontSheet.getSubimage(letterPos.x, letterPos.y, FONT_WIDTH, FONT_HEIGHT);
//int textureID = TextureLoader.loadGLTexture(letterImage);
//letterImage = null;
int width = fontSheet.getWidth(); int height = fontSheet.getHeight();
double d[] = {(double)letterPos.x/width, (double)letterPos.y/height, (double)(letterPos.x+FONT_WIDTH)/width, (double)(letterPos.y+FONT_HEIGHT)/height};
GL11.glPushMatrix();
GL11.glTranslatef(pos.x, pos.y, 0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2d(d[0], d[1]);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2d(d[2], d[1]);
GL11.glVertex2f(dim.x, 0);
GL11.glTexCoord2d(d[2], d[3]);
GL11.glVertex2f(dim.x, dim.y);
GL11.glTexCoord2d(d[0], d[3]);
GL11.glVertex2f(0, dim.y);
}
GL11.glEnd();
GL11.glPopMatrix();
//GL11.glDeleteTextures(textureID);
}

Categories