Related
I am trying to make my particle system generate particles one by one, rather than all at the same time. My code currently will generate all 100 particles instantly.
I have not tried much as I am new to coding.
I have a setup where I call and updated my particle class, and a class that has all my parameters of the particle system.
int num = 100;
Particle[] p = new Particle[num];
void setup() {
size(1080, 720);
colorMode(HSB);
for (int i = 0; i < num; i ++) {
p[i] = new Particle(new PVector(random(width), random(height)), 100, 150);
}
stroke(255);
}
void draw() {
background(0);
for (int i = 0; i < num; i ++) {
p[i].update(p, i);
}
}
class Particle {
PVector pos;
PVector vel;
float r, mr;
float spd = 0.1;
float max = 2;
Particle(PVector pos, float r, float mr) {
this.pos = pos;
this.r = r;
this.mr = mr;
vel = new PVector(random(-1, 1), random(-1, 1));
}
void update(Particle[] p, int i) {
float h = map(mouseX, 0, width, 0, 255);
pos.add(vel);
if (pos.x < -10) pos.x = width;
if (pos.x > width + 10) pos.x = 0;
if (pos.y < -10) pos.y = height;
if (pos.y > height + 10) pos.y = 0;
vel.x = constrain(vel.x + random(-spd, spd), -max, max);
vel.y = constrain(vel.y + random(-spd, spd), -max, max);
for (int j = i + 1; j < p.length; j ++) {
float ang = atan2(pos.y - p[j].pos.y, pos.x - p[j].pos.x);
float dist = pos.dist(p[j].pos);
if (dist < r) {
stroke(h, 255, map(dist, 0, r, 255, 0));
strokeWeight(map(dist, 0, r, 3, 0));
line(pos.x, pos.y, p[j].pos.x, p[j].pos.y);
float force = map(dist, 0, r, 4, 0);
vel.x += force * cos(ang);
vel.y += force * sin(ang);
}
}
float ang = atan2(pos.y - mouseY, pos.x - mouseX);
float dist = pos.dist(new PVector(mouseX, mouseY));
if (dist < r) {
stroke(0, 0, map(dist, 0, r, 255, 0));
strokeWeight(map(dist, 0, r, 3, 0));
line(pos.x, pos.y, mouseX, mouseY);
float force = map(dist, 0, r, 30, 0);
vel.x += force * cos(ang);
vel.y += force * sin(ang);
}
noStroke();
fill(h, 255, 255);
ellipse(pos.x, pos.y, 5, 5);
}
}
Create an ArrayList of particles, but don't add any particle in setup():
ArrayList<Particle> paticles = new ArrayList<Particle>();
void setup() {
size(400, 400);
colorMode(HSB);
stroke(255);
}
Consecutively add the particles in draw(). The function millis() is used to get the time since the program was started:
void draw() {
int num = 100;
int interval = 100; // 0.5 seconds
int time = millis(); // milliseconds since starting the program
if (paticles.size() < num && paticles.size()*interval+5000 < time) {
paticles.add(new Particle(new PVector(random(width), random(height)), 100, 150));
}
background(0);
for (int i = 0; i < paticles.size(); i ++) {
Particle p = paticles.get(i);
p.update(paticles, i);
}
}
Note, the class Particle has to be adapted, because it has to operate with the ArrayList of variable length rather than the array with fixed length:
class Particle {
PVector pos;
PVector vel;
float r, mr;
float spd = 0.1;
float max = 2;
Particle(PVector pos, float r, float mr) {
this.pos = pos;
this.r = r;
this.mr = mr;
vel = new PVector(random(-1, 1), random(-1, 1));
}
void update(ArrayList<Particle> paticles, int i) {
float h = map(mouseX, 0, width, 0, 255);
pos.add(vel);
if (pos.x < -10) pos.x = width;
if (pos.x > width + 10) pos.x = 0;
if (pos.y < -10) pos.y = height;
if (pos.y > height + 10) pos.y = 0;
vel.x = constrain(vel.x + random(-spd, spd), -max, max);
vel.y = constrain(vel.y + random(-spd, spd), -max, max);
for (int j = i + 1; j < paticles.size(); j ++) {
Particle pj = paticles.get(j);
float ang = atan2(pos.y - pj.pos.y, pos.x - pj.pos.x);
float dist = pos.dist(pj.pos);
if (dist < r) {
stroke(h, 255, map(dist, 0, r, 255, 0));
strokeWeight(map(dist, 0, r, 3, 0));
line(pos.x, pos.y, pj.pos.x, pj.pos.y);
float force = map(dist, 0, r, 4, 0);
vel.x += force * cos(ang);
vel.y += force * sin(ang);
}
}
float ang = atan2(pos.y - mouseY, pos.x - mouseX);
float dist = pos.dist(new PVector(mouseX, mouseY));
if (dist < r) {
stroke(0, 0, map(dist, 0, r, 255, 0));
strokeWeight(map(dist, 0, r, 3, 0));
line(pos.x, pos.y, mouseX, mouseY);
float force = map(dist, 0, r, 30, 0);
vel.x += force * cos(ang);
vel.y += force * sin(ang);
}
noStroke();
fill(h, 255, 255);
ellipse(pos.x, pos.y, 5, 5);
}
}
I'm trying to always show the front of a 3D font to the user. I tried rotating the font when rotating the camera, but never could get it to work.
I currently have this:
I'm trying to do this (font always faces front):
TrueTypeFont.java
package com.displee.render.font;
import lombok.AllArgsConstructor;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* A TrueType font implementation originally for Slick, edited for Bobjob's Engine
* #original author James Chambers (Jimmy)
* #original author Jeremy Adams (elias4444)
* #original author Kevin Glass (kevglass)
* #original author Peter Korzuszek (genail)
* #new version edited by David Aaron Muhar (bobjob)
*/
public class TrueTypeFont {
public final static int ALIGN_LEFT = 0, ALIGN_RIGHT = 1, ALIGN_CENTER = 2;
/**
* Array that holds necessary information about the font characters
*/
private IntObject[] charArray = new IntObject[256];
/**
* Map of user defined font characters (Character <-> IntObject)
*/
private Map customChars = new HashMap();
/**
* Boolean flag on whether AntiAliasing is enabled or not
*/
private boolean antiAlias;
/**
* Font's size
*/
private int fontSize = 0;
/**
* Font's height
*/
private int fontHeight = 0;
/**
* Texture used to cache the font 0-255 characters
*/
private int fontTextureID;
/**
* Default font texture width
*/
private int textureWidth = 512;
/**
* Default font texture height
*/
private int textureHeight = 512;
/**
* A reference to Java's AWT Font that we create our font texture from
*/
private Font font;
/**
* The font metrics for our Java AWT font
*/
private FontMetrics fontMetrics;
private int correctL = 9, correctR = 8;
private class IntObject {
/**
* Character's width
*/
public int width;
/**
* Character's height
*/
public int height;
/**
* Character's stored x position
*/
public int storedX;
/**
* Character's stored y position
*/
public int storedY;
}
public TrueTypeFont(Font font, boolean antiAlias, char[] additionalChars) {
this.font = font;
this.fontSize = font.getSize() + 3;
this.antiAlias = antiAlias;
createSet(additionalChars);
fontHeight -= 1;
if (fontHeight <= 0) {
fontHeight = 1;
}
}
public TrueTypeFont(Font font, boolean antiAlias) {
this(font, antiAlias, null);
}
public void setCorrection(boolean on) {
if (on) {
correctL = 2;
correctR = 1;
} else {
correctL = 0;
correctR = 0;
}
}
private BufferedImage getFontImage(char ch) {
// Create a temporary image to extract the character's size
BufferedImage tempfontImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) tempfontImage.getGraphics();
if (antiAlias == true) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
g.setFont(font);
fontMetrics = g.getFontMetrics();
int charwidth = fontMetrics.charWidth(ch) + 8;
if (charwidth <= 0) {
charwidth = 7;
}
int charheight = fontMetrics.getHeight() + 3;
if (charheight <= 0) {
charheight = fontSize;
}
// Create another image holding the character we are creating
BufferedImage fontImage;
fontImage = new BufferedImage(charwidth, charheight, BufferedImage.TYPE_INT_ARGB);
Graphics2D gt = (Graphics2D) fontImage.getGraphics();
if (antiAlias == true) {
gt.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
gt.setFont(font);
gt.setColor(Color.WHITE);
int charx = 3;
int chary = 1;
gt.drawString(String.valueOf(ch), (charx), (chary) + fontMetrics.getAscent());
//fontImage = ImageUtils.flipVertically(fontImage);
//fontImage = ImageUtils.flipHorizontally(fontImage);
//fontImage = ImageUtils.flipHorizontallyAndVertically(fontImage);
return fontImage;
}
private void createSet(char[] customCharsArray) {
// If there are custom chars then I expand the font texture twice
if (customCharsArray != null && customCharsArray.length > 0) {
textureWidth *= 2;
}
// In any case this should be done in other way. Texture with size 512x512
// can maintain only 256 characters with resolution of 32x32. The texture
// size should be calculated dynamicaly by looking at character sizes.
try {
BufferedImage imgTemp = new BufferedImage(textureWidth, textureHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) imgTemp.getGraphics();
g.setColor(new Color(0, 0, 0, 1));
g.fillRect(0, 0, textureWidth, textureHeight);
int rowHeight = 0;
int positionX = 0;
int positionY = 0;
int customCharsLength = (customCharsArray != null) ? customCharsArray.length : 0;
for (int i = 0; i < 256 + customCharsLength; i++) {
// get 0-255 characters and then custom characters
char ch = (i < 256) ? (char) i : customCharsArray[i - 256];
BufferedImage fontImage = getFontImage(ch);
IntObject newIntObject = new IntObject();
newIntObject.width = fontImage.getWidth();
newIntObject.height = fontImage.getHeight();
if (positionX + newIntObject.width >= textureWidth) {
positionX = 0;
positionY += rowHeight;
rowHeight = 0;
}
newIntObject.storedX = positionX;
newIntObject.storedY = positionY;
if (newIntObject.height > fontHeight) {
fontHeight = newIntObject.height;
}
if (newIntObject.height > rowHeight) {
rowHeight = newIntObject.height;
}
// Draw it here
g.drawImage(fontImage, positionX, positionY, null);
positionX += newIntObject.width;
if (i < 256) { // standard characters
charArray[i] = newIntObject;
} else { // custom characters
customChars.put(new Character(ch), newIntObject);
}
fontImage = null;
}
fontTextureID = loadImage(imgTemp);
//.getTexture(font.toString(), imgTemp);
} catch (Exception e) {
System.err.println("Failed to create font.");
e.printStackTrace();
}
}
private void drawQuad(float drawX, float drawY, float drawX2, float drawY2, float srcX, float srcY, float srcX2, float srcY2, float z) {
float DrawWidth = drawX2 - drawX;
float DrawHeight = drawY2 - drawY;
float TextureSrcX = srcX / textureWidth;
float TextureSrcY = srcY / textureHeight;
float SrcWidth = srcX2 - srcX;
float SrcHeight = srcY2 - srcY;
float RenderWidth = (SrcWidth / textureWidth);
float RenderHeight = (SrcHeight / textureHeight);
GL11.glTexCoord2f(TextureSrcX, TextureSrcY);
GL11.glVertex3f(drawX, drawY, z);
GL11.glTexCoord2f(TextureSrcX, TextureSrcY + RenderHeight);
GL11.glVertex3f(drawX, drawY + DrawHeight, z);
GL11.glTexCoord2f(TextureSrcX + RenderWidth, TextureSrcY + RenderHeight);
GL11.glVertex3f(drawX + DrawWidth, drawY + DrawHeight, z);
GL11.glTexCoord2f(TextureSrcX + RenderWidth, TextureSrcY);
GL11.glVertex3f(drawX + DrawWidth, drawY, z);
}
public int getWidth(String whatchars) {
int totalwidth = 0;
IntObject intObject = null;
int currentChar = 0;
for (int i = 0; i < whatchars.length(); i++) {
currentChar = whatchars.charAt(i);
if (currentChar < 256) {
intObject = charArray[currentChar];
} else {
intObject = (IntObject) customChars.get(new Character((char) currentChar));
}
if (intObject != null) {
totalwidth += intObject.width;
}
}
return totalwidth;
}
public int getHeight() {
return fontHeight;
}
public int getHeight(String HeightString) {
return fontHeight;
}
public int getLineHeight() {
return fontHeight;
}
public void drawString(float x, float y, float z, String whatchars, float scaleX, float scaleY) {
drawString(x, y, z, whatchars, 0, whatchars.length() - 1, scaleX, scaleY, ALIGN_LEFT);
}
public void drawString(float x, float y, float z, String whatchars, float scaleX, float scaleY, int format) {
drawString(x, y, z, whatchars, 0, whatchars.length() - 1, scaleX, scaleY, format);
}
public void drawString(float x, float y, float z, String whatchars, int startIndex, int endIndex, float scaleX, float scaleY, int format) {
IntObject intObject = null;
int charCurrent;
int totalwidth = 0;
int i = startIndex, d, c;
float startY = 0;
switch (format) {
case ALIGN_RIGHT: {
d = -1;
c = correctR;
while (i < endIndex) {
if (whatchars.charAt(i) == '\n') {
startY -= fontHeight;
}
i++;
}
break;
}
case ALIGN_CENTER: {
for (int l = startIndex; l <= endIndex; l++) {
charCurrent = whatchars.charAt(l);
if (charCurrent == '\n') {
break;
}
if (charCurrent < 256) {
intObject = charArray[charCurrent];
} else {
intObject = (IntObject) customChars.get(new Character((char) charCurrent));
}
totalwidth += intObject.width - correctL;
}
totalwidth /= -2;
}
case ALIGN_LEFT:
default: {
d = 1;
c = correctL;
break;
}
}
java.util.List<QuadObject> list = new ArrayList<>(endIndex - startIndex);
while (i >= startIndex && i <= endIndex) {
charCurrent = whatchars.charAt(i);
if (charCurrent < 256) {
intObject = charArray[charCurrent];
} else {
intObject = (IntObject) customChars.get(new Character((char) charCurrent));
}
if (intObject != null) {
if (d < 0) {
totalwidth += (intObject.width - c) * d;
}
if (charCurrent == '\n') {
startY -= fontHeight * d;
totalwidth = 0;
if (format == ALIGN_CENTER) {
for (int l = i + 1; l <= endIndex; l++) {
charCurrent = whatchars.charAt(l);
if (charCurrent == '\n') {
break;
}
if (charCurrent < 256) {
intObject = charArray[charCurrent];
} else {
intObject = (IntObject) customChars.get(new Character((char) charCurrent));
}
totalwidth += intObject.width - correctL;
}
totalwidth /= -2;
}
//if center get next lines total width/2;
} else {
QuadObject quad = new QuadObject((totalwidth + intObject.width) * scaleX + x, startY * scaleY + y, totalwidth * scaleX + x, (startY + intObject.height) * scaleY + y, intObject.storedX + intObject.width, intObject.storedY + intObject.height, intObject.storedX, intObject.storedY, z);
list.add(quad);
if (d > 0) {
totalwidth += (intObject.width - c) * d;
}
}
i += d;
}
}
float centerX = 0;
for(QuadObject quad : list) {
centerX += quad.drawX + (quad.drawX2 - quad.drawX);
}
centerX /= 2.0f;
float centerY = 0;
for(QuadObject quad : list) {
centerY += quad.drawY + (quad.drawY2 - quad.drawY);
}
centerY /= 2.0f;
//GL11.glTranslatef( -centerX, -centerY, -z);
//GL11.glTranslatef(0, 0, -z);
GL11.glRotatef(-Test3DFont.rotation.x, 0.0f, 0.0f, 0.0f);
GL11.glRotatef(-Test3DFont.rotation.y, 0.0f, 1.0f, 0.0f);
//GL11.glRotatef(-Test3DFont.rotation.z, 0.0f, 0.0f, 1.0f);
//GL11.glTranslatef(0, 0, z);
//GL11.glTranslatef(centerX, centerY, z); // M1 - 2nd translation
GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureID);
GL11.glBegin(GL11.GL_QUADS);
for(QuadObject quad : list) {
drawQuad(quad.drawX, quad.drawY, quad.drawX2, quad.drawY2, quad.srcX, quad.srcY, quad.srcX2, quad.srcY2, quad.z);
}
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnd();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
}
public static int loadImage(BufferedImage bufferedImage) {
try {
short width = (short) bufferedImage.getWidth();
short height = (short) bufferedImage.getHeight();
//textureLoader.bpp = bufferedImage.getColorModel().hasAlpha() ? (byte)32 : (byte)24;
int bpp = (byte) bufferedImage.getColorModel().getPixelSize();
ByteBuffer byteBuffer;
DataBuffer db = bufferedImage.getData().getDataBuffer();
if (db instanceof DataBufferInt) {
int intI[] = ((DataBufferInt) (bufferedImage.getData().getDataBuffer())).getData();
byte newI[] = new byte[intI.length * 4];
for (int i = 0; i < intI.length; i++) {
byte b[] = intToByteArray(intI[i]);
int newIndex = i * 4;
newI[newIndex] = b[1];
newI[newIndex + 1] = b[2];
newI[newIndex + 2] = b[3];
newI[newIndex + 3] = b[0];
}
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(newI);
} else {
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(((DataBufferByte) (bufferedImage.getData().getDataBuffer())).getData());
}
byteBuffer.flip();
int internalFormat = GL11.GL_RGBA8, format = GL11.GL_RGBA;
IntBuffer textureId = BufferUtils.createIntBuffer(1);
;
GL11.glGenTextures(textureId);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId.get(0));
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL11.GL_UNSIGNED_BYTE, byteBuffer.order(ByteOrder.nativeOrder()));
return textureId.get(0);
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
return -1;
}
public static boolean isSupported(String fontname) {
Font font[] = getFonts();
for (int i = font.length - 1; i >= 0; i--) {
if (font[i].getName().equalsIgnoreCase(fontname)) {
return true;
}
}
return false;
}
public static Font[] getFonts() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
}
public static byte[] intToByteArray(int value) {
return new byte[]{(byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value};
}
public void destroy() {
IntBuffer scratch = BufferUtils.createIntBuffer(1);
scratch.put(0, fontTextureID);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
GL11.glDeleteTextures(scratch);
}
#AllArgsConstructor
private class QuadObject {
private float drawX;
private float drawY;
private float drawX2;
private float drawY2;
private float srcX;
private float srcY;
private float srcX2;
private float srcY2;
private float z;
}
}
Test3DFont.java
package com.displee.render.font;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.vector.Vector3f;
import java.awt.*;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.gluPerspective;
public class Test3DFont {
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
private static final float FOV = 45f;
private static final float NEAR = 0.1f;
private static final float FAR = 1000f;
private static boolean mousePressed;
private static Vector3f startCoordinations = new Vector3f();
private static float scale = 0.05f;
public static Vector3f rotation = new Vector3f(0, 0, 0);
private static Vector3f startRotation = new Vector3f();
private static TrueTypeFont font;
private static boolean running = true;
public static void main(String[] args) throws Exception {
initializeDisplay();
font = new TrueTypeFont(new Font("serif", Font.PLAIN, 30), true);
initializeGL();
while(running) {
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
handleMouse();
font.drawString(0, 0, 0, "Test", 0.1f, 0.1f);
loadDefaultRotation();
setViewport();
drawGrid();
Display.sync(60);
Display.update();
if (Display.isCloseRequested()) {
break;
}
}
font.destroy();
Display.destroy();
}
private static void initializeDisplay() throws LWJGLException {
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.create();
setViewport();
}
public static void set2DMode() {
//GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
GL11.glPushMatrix(); // Store The Projection Matrix
GL11.glLoadIdentity(); // Reset The Projection Matrix
GL11.glOrtho(0, WIDTH, 0, HEIGHT, -1, 1); // Set Up An Ortho Screen
GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
GL11.glPushMatrix(); // Store The Modelview Matrix
GL11.glLoadIdentity(); // Reset The Modelview Matrix
}
public static void set3DMode() {
GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
GL11.glPopMatrix(); // Restore The Old Projection Matrix
GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
GL11.glPopMatrix(); // Restore The Old Projection Matrix
//GL11.glEnable(GL11.GL_DEPTH_TEST);
}
private static void setViewport() {
glViewport(0, 0, WIDTH, HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(FOV, (float) WIDTH / (float) HEIGHT, NEAR, FAR);
glMatrixMode(GL_MODELVIEW);
}
private static void initializeGL() {
glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);
glEnable(GL_BLEND);
glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
private static void handleMouse() {
scale += Mouse.getDWheel() > 0 ? 0.005f : Mouse.getDWheel() < 0 ? -0.005f : 0;
int x = Mouse.getY();
int y = Mouse.getX();
if (!mousePressed) {
mousePressed = Mouse.isButtonDown(0);
if (mousePressed) {
startCoordinations.set((float) x, (float) y, 0.0f);
startRotation = new Vector3f(rotation);
}
} else if (!Mouse.isButtonDown(0)) {
mousePressed = false;
}
if (!mousePressed) {
return;
}
float differenceX = x - startCoordinations.x;
float differenceY = y - startCoordinations.y;
rotation.set(startRotation.x - (differenceX * 0.5F), startRotation.y + (differenceY * 0.5F), 0);
}
private static void loadDefaultRotation() {
glLoadIdentity();
Vector3f cameraPosition = new Vector3f();
glTranslatef(cameraPosition.x, cameraPosition.y, -10);
glRotatef(rotation.x, 1.0F, 0.0F, 0.0F);
glRotatef(rotation.y, 0.0F, 1.0F, 0.0F);
glRotatef(rotation.z, 0.0F, 0.0F, 1.0F);
glScalef(scale, scale, scale);
}
private static void drawGrid() {
glColor4f(0.7176471f, 0.7176471f, 0.7176471f, 1.0f);
glBegin(GL_LINES);
float size = 50;
float step = 10;
for (float i = -size; i <= size; i += step) {
glVertex3f(i, 0, size);
glVertex3f(i, 0, -size);
glVertex3f(size, 0, i);
glVertex3f(-size, 0, i);
}
glEnd();
}
public static int[] getScreenCoords(double x, double y, double z) {
FloatBuffer screenCoords = BufferUtils.createFloatBuffer(4);
IntBuffer viewport = BufferUtils.createIntBuffer(16);
FloatBuffer modelView = BufferUtils.createFloatBuffer(16);
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
boolean result = GLU.gluProject((float) x, (float) y, (float) z, modelView, projection, viewport, screenCoords);
if (result) {
return new int[] { (int) screenCoords.get(0), (int) screenCoords.get(1) };
}
return null;
}
}
Can anyone help me with this? How can I make it so I always see the front of the font?
Update 1:
I've got it almost working by rotating the quads. I've added the following code in the drawString method before enabling texture 2D:
GL11.glRotatef(-Test3DFont.rotation.x, 0.0f, 0.0f, 0.0f);
GL11.glRotatef(-Test3DFont.rotation.y, 0.0f, 1.0f, 0.0f);
I've updated the code. It currently looks like this:
I finally fixed it by pushing a matrix and using the original x, y and z coords in the translation. I also had to subtract 180 from the rotation because that's my starting rotation. Ended up with the following code:
GL11.glPushMatrix();
GL11.glTranslatef(x, y, z);
GL11.glRotatef(180 - rotation.y, 0.0f, 1.0f, 0.0f);
GL11.glTranslatef(-x, -y, -z);
GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureID);
GL11.glBegin(GL11.GL_QUADS);
for(QuadObject quad : list) {
drawQuad(quad.drawX, quad.drawY, quad.drawX2, quad.drawY2, quad.srcX, quad.srcY, quad.srcX2, quad.srcY2, quad.z);
}
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnd();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
GL11.glPopMatrix();
Table t1;
import ddf.minim.*;
AudioPlayer player;
Minim minim;
int stickColR=0;
int stickColG=0;
int stickColB=0;
int counter=0;
//--------------
void setup(){
size(1000,600);
smooth();
t1 = new Table(1000,600);
t1.startGame();
//sound player setup
minim= new Minim(this);
player=minim.loadFile("ballsound.mp3");
}
//--------------
void draw(){
strokeWeight(10);
stroke(255,0,0);
fill(26, 218, 35);
rect(0, 0, 1000, 600);
fill(0);
noStroke();
ellipse(0, 0, 100, 100);
ellipse(1000, 0, 100, 100);
ellipse(0, 600, 100, 100);
ellipse(1000, 600, 100, 100);
t1.updatePos(); //calling the function to update the position of the balls
t1.visualize(); // Function responsible for drawing the balls
}
//--------------
void mousePressed(){
t1.mousePressed(mouseX-t1.x,mouseY-t1.y);
}
//--------------
void mouseReleased(){
t1.mouseReleased(mouseX-t1.x,mouseY-t1.y);
}
//=============================
class Table{
boolean GameIsOver=false;
float drag = 0.99;
float bounce = 0.4;
float wallBounce = 0.3;
float pushFactor = 0.4;
float maxPush = 20;
color[] ballColors = new color[]{color (255), color (216,7,17),color(17,242,225), color ( #45B4CE) , color ( #6A6347) , color (#E80909) ,color (#CEA9A9)};
Ball[] balls;
Ball selectedBall;
int x,y,width,height;
//--------------
Table(int w, int h){
width = w;
height = h;
}
//--------------
void startGame(){
buildBalls(5);
}
//--------------
void buildBalls(int count){
balls = new Ball[2*count+1];
int x_coor_red=600;
int y_coor_red=300;
int x_coor_green=626;
int y_coor_green=313;
for(int i=0;i<count;i++)
{
balls[i] = new Ball(x_coor_red, y_coor_red,i+1, this);
x_coor_red+=26;
y_coor_red-=13;
if(i>=3)
{
x_coor_red-=26;
y_coor_red+=26;
}
}
for(int i=0;i<count;i++)
{
balls[count+i] = new Ball( x_coor_green, y_coor_green,i+2, this);
x_coor_green+=26;
y_coor_green+=13;
if(i==1)
{
x_coor_green-=26;
y_coor_green-=20;
}
if(i==2)
{
y_coor_green-=20;
}
if(i==3)
{
x_coor_green-=45;
}
}
balls[2*count] = new Ball( 0.5*(width), 0.5*(height),0, this);
}
//--------------
void updatePos(){
//simulation
for(int i=0;i<balls.length;i++)
balls[i].update();
//collision detection
for(int i=0;i<balls.length;i++)
for(int j=i+1;j<balls.length;j++)
balls[i].collisionDetect(balls[j]);
}
//--------------
void visualize(){
translate(x,y);
noStroke();
//draw stick
if(mousePressed && selectedBall!= null && (mouseX<=26+selectedBall.x || mouseX>26-selectedBall.x) && selectedBall.ballColor==color(255)){
stickColR+=2;
stickColB+=2;
strokeWeight(4);
stroke(stickColR, stickColG, stickColB);
line ( mouseX , mouseY , mouseX + cos (atan2 ( mouseY -selectedBall.y , mouseX - selectedBall.x) )*300 , mouseY + sin( atan2 ( mouseY - selectedBall.y , mouseX -selectedBall.x ))*300);
}
//drawing
for(int i=0;i<balls.length;i++){
balls[i].visualize();
//Balls"disappearing" in corners
if(balls[i].x<50 && (balls[i].y<50 || balls[i].y>550) || balls[i].x>950 &&(balls[i].y<50 || balls[i].y>550)){
player.rewind();
player.play();
if(balls[i].ballColor==color(255))
{
textSize(25);
text("Cue Ball Sunk. GAME OVER",350,560);
}
fill(0);
ellipse(0,0,100,100);
ellipse(1000, 0, 100, 100);
ellipse(0, 600, 100, 100);
ellipse(1000, 600, 100, 100);
balls[i].x=1200;
balls[i].y=0;
counter++;
if (balls[i].ballColor != 255 && counter>=3)
{
textSize(25);
text("YOU WIN", 350,560);
}
}
}
}
//--------------
float kineticEnergy(){
float energy=0;
for(int i=0;i<balls.length;i++)
energy += mag( balls[i].vx, balls[i].vy );
return energy;
}
//--------------
void mousePressed(int mx, int my){
for(int i=0;i<balls.length;i++)
if( dist(balls[i].x,balls[i].y,mx,my) < balls[i].radius) {
selectedBall = balls[i];
break;
}
}
//--------------
void mouseReleased(int mx, int my){
if(selectedBall != null){
float px = (selectedBall.x-mx) * pushFactor;
float py = (selectedBall.y-my) * pushFactor;
float push = mag(px,py);
stickColR=0;
stickColB=0;
if( push > maxPush ){
px = maxPush*px/push;
py = maxPush*py/push;
}
selectedBall.push(px,py);
}
selectedBall = null;
}
}
class Ball{
float x,y,vx,vy,radius,diameter;
int type;
Table table;
color ballColor;
//--------------
Ball(float x, float y, int type, Table t){
this.x = x;
this.y = y;
this.type = type;
diameter = 26;
radius = diameter/2;
table = t;
ballColor = table.ballColors[type];
}
//--------------
void update(){
vx *= table.drag;
vy *= table.drag;
x += vx;
y += vy;
wallBounce();
}
//--------------
void wallBounce(){
if(x<=radius){
vx = -table.wallBounce*vx;
x = radius;
player.rewind();
player.play();
}
if(x>=t1.width-radius){
vx = -table.wallBounce*vx;
x = table.width-radius;
player.rewind();
player.play();
}
if(y<=radius){
vy = -table.wallBounce*vy;
y = radius;
player.rewind();
player.play();
}
if(y>=t1.height-radius){
vy = -table.wallBounce*vy;
y = table.height-radius;
player.rewind();
player.play();
}
}
//--------------
void visualize(){
fill(ballColor);
stroke(0);
strokeWeight(2);
stroke(0);
ellipse(x,y,diameter,diameter);
}
//--------------
void push(float dx, float dy){
vx += dx;
vy += dy;
}
//--------------
void collisionDetect(Ball b){
float distance = dist(x,y,b.x,b.y);
if( distance < diameter && (b.x>50 && (b.y>50 || b.y<550) || b.x<950 &&(b.y>50 || b.y<550))){
float vxSum = 0.5*(vx + b.vx);
float vySum = 0.5*(vy + b.vy);
float forceMagnitude = ((b.x-x)*(vx-vxSum) + (b.y-y)*(vy-vySum));
float xForce = 0.25*(x-b.x)*forceMagnitude/distance;
float yForce = 0.25*(y-b.y)*forceMagnitude/distance;
vx = vx + table.bounce * xForce;
vy = vy + table.bounce * yForce;
b.vx = b.vx - table.bounce * xForce;
b.vy = b.vy - table.bounce * yForce;
b.x = x + (diameter+1)*(b.x-x)/distance;
b.y = y + (diameter+1)*(b.y-y)/distance;
player.rewind();
player.play();
}
}
}
Im making a pool game in processing and I'm almost done but I'm stuck here. I want to add a counter that counts when a ball has been in the corner, then once the counter equals ten, the number of balls, it will display the winning message. I think something is going wrong in that the counter is being reset each time since it's in draw? But I'm not sure where else to initialize it. Btw, right now I just have it >= 3 so that I can quickly see if it's working. Thanks all
due to my low reputation, I have to show you my solution even though I think I haven't fixed all the bugs in your code.
I think your bug stated in the question has little relationship with the counter variable. I ran your code and found that you tried to hide the "disappeared" ball by changing coordinates. It means that "disappeared" balls can still be qualified to the if statement below, and as the result, value of counter will keep increasing.
//Balls"disappearing" in corners
if(balls[i].x<50 && (balls[i].y<50 || balls[i].y>550) || balls[i].x>950 &&(balls[i].y<50 || balls[i].y>550))
So you can add a boolean field to the Ball class
class Ball{
float x,y,vx,vy,radius,diameter;
int type;
Table table;
color ballColor;
// add this variable.
boolean disappeared = false;
// your constructor, wallBounce(), push(), collisionDetect()
void visualize(){
// only draw the ball when it hasn't disappeared.
if(!this.disappeared) {
fill(ballColor);
stroke(0);
strokeWeight(2);
stroke(0);
ellipse(x,y,diameter,diameter);
}
}
}
and then use it to avoid double counting.
// other code in visualize()
if(!balls[i].disappeared) {
counter++;
balls[i].disappeared = true;
}
// other code
Table t1;
import ddf.minim.*;
AudioPlayer player;
Minim minim;
int stickColR=0;
int stickColG=0;
int stickColB=0;
float counter;
boolean isAllIn = false;
//--------------
void setup() {
counter=0;
size(1000, 600);
smooth();
t1 = new Table(1000, 600);
t1.startGame();
//sound player setup
minim= new Minim(this);
player=minim.loadFile("ballsound.mp3");
}
//--------------
void draw() {
strokeWeight(10);
stroke(255, 0, 0);
fill(26, 218, 35);
rect(0, 0, 1000, 600);
fill(0);
noStroke();
ellipse(0, 0, 100, 100);
ellipse(1000, 0, 100, 100);
ellipse(0, 600, 100, 100);
ellipse(1000, 600, 100, 100);
t1.updatePos(); //calling the function to update the position of the balls
t1.visualize(); // Function responsible for drawing the balls
}
//--------------
void mousePressed() {
t1.mousePressed(mouseX-t1.x, mouseY-t1.y);
}
//--------------
void mouseReleased() {
t1.mouseReleased(mouseX-t1.x, mouseY-t1.y);
}
//=============================
class Table {
float drag = 0.99;
float bounce = 0.4;
float wallBounce = 0.3;
float pushFactor = 0.4;
float maxPush = 20;
color[] ballColors = new color[]{color (255), color (216, 7, 17), color(17, 242, 225), color ( #45B4CE), color ( #6A6347), color (#E80909), color (#CEA9A9)};
Ball[] balls;
Ball selectedBall;
int x, y, width, height;
//--------------
Table(int w, int h) {
width = w;
height = h;
}
//--------------
void startGame() {
buildBalls(5);
}
void restart() {
t1 = new Table(1000, 600);
t1.startGame();
}
//--------------
void buildBalls(int count) {
balls = new Ball[2*count+1];
int x_coor_red=600;
int y_coor_red=300;
int x_coor_green=626;
int y_coor_green=313;
for (int i=0; i<count; i++)
{
balls[i] = new Ball(x_coor_red, y_coor_red, i+1, this);
x_coor_red+=26;
y_coor_red-=13;
if (i>=3)
{
x_coor_red-=26;
y_coor_red+=26;
}
}
for (int i=0; i<count; i++)
{
balls[count+i] = new Ball( x_coor_green, y_coor_green, i+2, this);
x_coor_green+=26;
y_coor_green+=13;
if (i==1)
{
x_coor_green-=26;
y_coor_green-=20;
}
if (i==2)
{
y_coor_green-=20;
}
if (i==3)
{
x_coor_green-=45;
}
}
balls[2*count] = new Ball( 0.5*(width), 0.5*(height), 0, this);
}
//--------------
void updatePos() {
//simulation
for (int i=0; i<balls.length; i++)
balls[i].update();
//collision detection
for (int i=0; i<balls.length; i++)
for (int j=i+1; j<balls.length; j++)
balls[i].collisionDetect(balls[j]);
}
//--------------
void visualize() {
translate(x, y);
noStroke();
//draw stick
if (mousePressed && selectedBall!= null && (mouseX<=26+selectedBall.x || mouseX>26-selectedBall.x) && selectedBall.ballColor==color(255)) {
stickColR+=2;
stickColB+=2;
strokeWeight(4);
stroke(stickColR, stickColG, stickColB);
line ( mouseX, mouseY, mouseX + cos (atan2 ( mouseY -selectedBall.y, mouseX - selectedBall.x) )*300, mouseY + sin( atan2 ( mouseY - selectedBall.y, mouseX -selectedBall.x ))*300);
}
//drawing
for (int i=0; i<balls.length; i++) {
balls[i].visualize();
//Balls"disappearing" in corners
if (balls[i].x<50 && (balls[i].y<50 || balls[i].y>550) || balls[i].x>950 &&(balls[i].y<50 || balls[i].y>550)) {
player.rewind();
player.play();
if (balls[i].ballColor==color(255))
{
textSize(25);
text("Cue Ball Sunk. GAME OVER. Press any key to restart.", 170, 560);
if (keyPressed == true) {
t1.restart();
}
}
/*
fill(0);
ellipse(0, 0, 100, 100);
ellipse(1000, 0, 100, 100);
ellipse(0, 600, 100, 100);
ellipse(1000, 600, 100, 100);
balls[i].x=1200;
balls[i].y=0;
*/
if (!balls[i].disappeared) {
counter++;
balls[i].disappeared=true;
}
if ( counter>=3) {
textSize(25);
text("YOU WIN. Press any key to restart.", 300, 560);
if (keyPressed == true) {
t1.restart();
}
}
}
}
}
//--------------
float kineticEnergy() {
float energy=0;
for (int i=0; i<balls.length; i++)
energy += mag( balls[i].vx, balls[i].vy );
return energy;
}
//--------------
void mousePressed(int mx, int my) {
for (int i=0; i<balls.length; i++)
if ( dist(balls[i].x, balls[i].y, mx, my) < balls[i].radius) {
selectedBall = balls[i];
break;
}
}
//--------------
void mouseReleased(int mx, int my) {
if (selectedBall != null) {
float px = (selectedBall.x-mx) * pushFactor;
float py = (selectedBall.y-my) * pushFactor;
float push = mag(px, py);
stickColR=0;
stickColB=0;
if ( push > maxPush ) {
px = maxPush*px/push;
py = maxPush*py/push;
}
selectedBall.push(px, py);
}
selectedBall = null;
}
}
class Ball {
boolean disappeared = false;
float x, y, vx, vy, radius, diameter;
int type;
Table table;
color ballColor;
//--------------
Ball(float x, float y, int type, Table t) {
this.x = x;
this.y = y;
this.type = type;
diameter = 26;
radius = diameter/2;
table = t;
ballColor = table.ballColors[type];
}
//--------------
void update() {
vx *= table.drag;
vy *= table.drag;
x += vx;
y += vy;
wallBounce();
}
//--------------
void wallBounce() {
if (x<=radius) {
vx = -table.wallBounce*vx;
x = radius;
player.rewind();
player.play();
}
if (x>=t1.width-radius) {
vx = -table.wallBounce*vx;
x = table.width-radius;
player.rewind();
player.play();
}
if (y<=radius) {
vy = -table.wallBounce*vy;
y = radius;
player.rewind();
player.play();
}
if (y>=t1.height-radius) {
vy = -table.wallBounce*vy;
y = table.height-radius;
player.rewind();
player.play();
}
}
//--------------
void visualize() {
if (!this.disappeared) {
fill(ballColor);
stroke(0);
strokeWeight(2);
stroke(0);
ellipse(x, y, diameter, diameter);
}
}
//--------------
void push(float dx, float dy) {
vx += dx;
vy += dy;
}
//--------------
void collisionDetect(Ball b) {
float distance = dist(x, y, b.x, b.y);
if ( distance < diameter && (b.x>50 && (b.y>50 || b.y<550) || b.x<950 &&(b.y>50 || b.y<550))) {
float vxSum = 0.5*(vx + b.vx);
float vySum = 0.5*(vy + b.vy);
float forceMagnitude = ((b.x-x)*(vx-vxSum) + (b.y-y)*(vy-vySum));
float xForce = 0.25*(x-b.x)*forceMagnitude/distance;
float yForce = 0.25*(y-b.y)*forceMagnitude/distance;
vx = vx + table.bounce * xForce;
vy = vy + table.bounce * yForce;
b.vx = b.vx - table.bounce * xForce;
b.vy = b.vy - table.bounce * yForce;
b.x = x + (diameter+1)*(b.x-x)/distance;
b.y = y + (diameter+1)*(b.y-y)/distance;
player.rewind();
player.play();
}
}
}
I have a code in processing which contains points moving randomly. Those points seek the ball and start triangulate (shaping triangles). I want to display on them a folder of sequences images with opacity. So every time that an triangle is shaped will be textured with an image.
I have tried to use texture and loadimage function but it seems that the problem is that triangles is rendered rapidly with various points and texture can not be seen properly.
import processing.opengl.*;
float r1, r2;
void setup()
{
size(800, 800, OPENGL);
for (int j=0; j<numAgents; j++)
agents[j]=new agent();
for (int i=0; i<numMovers; i++)
movers[i]=new Mover();
smooth();
}
void draw()
{
background(0);
for (int i=0; i<numMovers; i++)
{
movers[i].update();
movers[i].checkEdges();
movers[i].display();
int closestAgentNumber=-1;
for (int j=0; j<numAgents; j++)
{
agents[j].checkEdges();
agents[j].display();
agents[j].update();
agents[j].repel();
float d = dist(agents[j].location.x, agents[j].location.y, movers[i].location.x, movers[i].location.y );
if (d < 100) {
closestAgentNumber=j;
}
if (d<200)
{
agents[j].behaviour=1;
agents[j].follow(movers[i].location.x, movers[i].location.y);
movers[i].hit = true;
}
else if (d>100) {
movers[i].hit = false;
agents[j].behaviour=0;
}
}
}
}
int numAgents= 100;
agent[]agents =new agent[numAgents];
class agent
{
PVector location;
PVector velocity;
PVector acceleration;
float topspeed;
float r1, r2;
// boolean connect=false;
int behaviour;
boolean follow=false;
//boolean follow= false;
agent()
{
float speed=800;
if (behaviour==0)
{
location= new PVector(random(0, speed), random(0, speed));
velocity= new PVector(1, 1);
acceleration= new PVector( random(-0.01, 0.01), random(-0.01, 0.01));
acceleration.normalize();
topspeed=5;
}
else if (behaviour==1)
{
// connect=true;
}
// Set to acceleration
}
void follow(float x, float y)
{
if (follow==true)
{
// follow==true;
// Our algorithm for calculating acceleration:
PVector moverPos = new PVector(x, y);
PVector dir = PVector.sub(moverPos, location); // Find vector pointing towards mouse
dir.normalize(); // Normalize
dir.mult(4); // Scale
acceleration = dir;
}
}
void update()
{
velocity.add(acceleration);
velocity.limit(topspeed);
location.add(velocity);
}
void display()
{
pushMatrix();
translate(location.x, location.y);
if (behaviour==1)
{
fill(255, 0, 0);
}
else if ( behaviour==0)
{
fill(255, 255, 255);
}
ellipse(0, 0, 4, 4);
strokeWeight(1);
popMatrix();
}
void checkEdges()
{
if (location.x < 0) {
location.x = 0;
velocity.x *= -1;
acceleration.mult(0.001);
}
if (location.x > 800) {
location.x = 800;
velocity.x *= -1;
acceleration.mult(0.001);
}
if (location.y < 0) {
location.y = 0;
velocity.y *= -1;
acceleration.mult(0.001);
}
if (location.y > 800) {
location.y = 800;
velocity.y *= -1;
acceleration.mult(0.001);
}
}
void repel()
{
for (int i=0; i<numAgents; i++) {
if ((agents[i].behaviour==1))
{
int k;
k=1;
for (int j=0; j<numAgents; j++)
{
//--------------
// float dm = agents[i].location.dist(agents[k].location);
float dm = dist(agents[j].location.x, agents[j].location.y, agents[i].location.x, agents[i].location.y);
if (dm < 50) {
agents[i].velocity.mult(-1);
agents[i].acceleration.mult(0.5);
agents[j].velocity.mult(-1);
agents[j].acceleration.mult(0.5);
}
else if (behaviour==0)
{
agents[i].velocity.mult(1);
agents[j].velocity.mult(1);
}
//float dm = dist(agents[i].location.x, agents[i].location.y, agents[j].location.x, agents[j].location.y);
// float dm = agents[i].location.dist(agents[j].location);
// int clr=(int) map (dm,0,100,200,0);
if (dm<180 && dm>100)
{
if ( k<2)
{
//println(dm);
//stroke(255,0,0);
r1 = agents[j].location.x;
r2 = agents[j].location.y;
k=k+1;
}
else
{
//fill(random(255),random(255),random(255),random(0,20));
//stroke(0,50);
// texture(A);
//fill(random(0,255),random(0,255),random(0,255),random(0, 40));
// stroke(140, 50);
fill(random(0, 255), random(0, 255), random(0, 255), random(0, 10));
stroke(140, 50);
beginShape();
//texture();
// image(A,agents[i].location.x, agents[i].location.y);
vertex(agents[i].location.x, agents[i].location.y);
vertex(r1, r2);
vertex(agents[j].location.x, agents[j].location.y);
endShape(CLOSE);
j=300;
}
}
}
/*void triangulate()
{
fill(random(0, 255), random(0, 255), random(0, 255), random(0, 40));
stroke(140, 50);
for (int i=0; i<numAgents; i++)
{
//gens[i].connect==true)
//if(! agents[i].connect)
if (agents[i].behaviour==1)
{
//println(agents[i]);
int k;
k=1;
for (int j=0; j<numAgents; j++)
{
float dm = dist(agents[i].location.x, agents[i].location.y, agents[j].location.x, agents[j].location.y);
// float dm = agents[i].location.dist(agents[j].location);
// int clr=(int) map (dm,0,100,200,0);
if (dm<180 && dm>100)
{
if ( k<2)
{
//println(dm);
//stroke(255,0,0);
}
}
}
}*/
}
}
}
}
int numMovers= 1;
Mover[]movers= new Mover[numMovers];
class Mover
{
PVector location;
PVector velocity;
PVector acceleration;
float topspeed;
boolean hit = false;
Mover()
{
float spead = 800;
location = new PVector(random(0,spead),random(0,spead));
velocity = new PVector(0,0);
acceleration = new PVector(random(-1,1),random(-1,1));//random initial acceleration
topspeed = 4;
}
void update()
{
// Motion 101! Velocity changes by acceleration. Location changes by velocity.
velocity.add(acceleration);
velocity.limit(topspeed);
location.add(velocity);
}
void display()
{
pushMatrix();
translate(location.x,location.y);
//fill(102,0,155,random(120,160));
//fill(32,225,245,127 + sin(frameCount*.01) * 127);
if(hit) fill(255,10,96,120);
else
fill(3,225,190,random(50,127));
ellipse(0,0,30,30);
noStroke();
popMatrix();
}
void checkEdges()
{
if(location.x < 0){
location.x = 0;
velocity.x *= -1;
acceleration.mult(0.001);
}
if(location.x > 800){
location.x = 800;
velocity.x *= -1;
acceleration.mult(0.001);
}
if(location.y < 0){
location.y = 0;
velocity.y *=- 1;
acceleration.mult(0.001);
}
if(location.y > 800){
location.y = 800;
velocity.y *= -1;
acceleration.mult(0.001);
}
}
}
You will need to use 3 Processing functions for this:
tint() - which you'll use for transparency (e.g. tint(255,127); will make the image/texture 50% transparent (127 of 255) )
texture() - this sets texture to a shape(beginShape(),endShape() block). You pass call it after beginShape() and then you pass two additional arguments when calling vertex(), which are your texture coordinates
textureMode() - If you always know the size of your texture image, this is optional, but it's handy to know about this. By default the texture mode is set to IMAGE meaning that for a 100x100 px image that you will map to a 300 units long quad for example, you will map the vertex corner positions with the texture coordinates as in the example bellow.
default texture mode (textureMode(IMAGE))
//assumes tex is already initialized/loaded PImage
beginShape();
texture(tex);
vertex(-150,-150,0, 0, 0);//top-left
vertex( 150,-150,0, 100, 0);//top-right
vertex( 150, 150,0, 100,100);//bottom-right
vertex(-150, 150,0, 0,100);//bottom-left
endShape();
The other option is to use NORMALIZED mode, which instead of actual pixel values, takes normalized values (between 0.0 and 1.0), so the above example in NORMALIZED mode is:
beginShape();
texture(tex);
vertex(-150,-150,0, 0.0,0.0);//top-left
vertex( 150,-150,0, 1.0,0.0);//top-right
vertex( 150, 150,0, 1.0,1.0);//bottom-right
vertex(-150, 150,0, 0.0,1.0);//bottom-left
endShape();
textureMode() is called usually once in setup() and the advantage is you won't have to worry about knowing all the dimensions of all your textures, especially when you use more than one texture in your sketch.
So, back to your code, you need to initialize the texture like so:
tex = loadImage("yourTextureImage.png");
textureMode(NORMALIZED);
and later in repel() function when you draw your shape, you would do this:
beginShape();
tint(255,127);
texture(tex);
vertex(agents[i].location.x, agents[i].location.y,0.0,0.0);//aditional u,v coordinates 0,0 - top left of texture
vertex(r1, r2,1.0,0.0);//top right texture coordinate
vertex(agents[j].location.x, agents[j].location.y,1.0,1.0);//bottom right texture coordinat
endShape(CLOSE);
So the full code would look like this:
import processing.opengl.*;
float r1, r2;
PImage tex;
void setup()
{
size(800, 800, OPENGL);
for (int j=0; j<numAgents; j++)
agents[j]=new agent();
for (int i=0; i<numMovers; i++)
movers[i]=new Mover();
tex = loadImage("yourImage.png");
textureMode(NORMALIZED);
smooth();
}
void draw()
{
background(0);
for (int i=0; i<numMovers; i++)
{
movers[i].update();
movers[i].checkEdges();
movers[i].display();
int closestAgentNumber=-1;
for (int j=0; j<numAgents; j++)
{
agents[j].checkEdges();
agents[j].display();
agents[j].update();
agents[j].repel();
float d = dist(agents[j].location.x, agents[j].location.y, movers[i].location.x, movers[i].location.y );
if (d < 100) {
closestAgentNumber=j;
}
if (d<200)
{
agents[j].behaviour=1;
agents[j].follow(movers[i].location.x, movers[i].location.y);
movers[i].hit = true;
}
else if (d>100) {
movers[i].hit = false;
agents[j].behaviour=0;
}
}
}
}
int numAgents= 100;
agent[]agents =new agent[numAgents];
class agent
{
PVector location;
PVector velocity;
PVector acceleration;
float topspeed;
float r1, r2;
// boolean connect=false;
int behaviour;
boolean follow=false;
//boolean follow= false;
agent()
{
float speed=800;
if (behaviour==0)
{
location= new PVector(random(0, speed), random(0, speed));
velocity= new PVector(1, 1);
acceleration= new PVector( random(-0.01, 0.01), random(-0.01, 0.01));
acceleration.normalize();
topspeed=5;
}
else if (behaviour==1)
{
// connect=true;
}
// Set to acceleration
}
void follow(float x, float y)
{
if (follow==true)
{
// follow==true;
// Our algorithm for calculating acceleration:
PVector moverPos = new PVector(x, y);
PVector dir = PVector.sub(moverPos, location); // Find vector pointing towards mouse
dir.normalize(); // Normalize
dir.mult(4); // Scale
acceleration = dir;
}
}
void update()
{
velocity.add(acceleration);
velocity.limit(topspeed);
location.add(velocity);
}
void display()
{
pushMatrix();
translate(location.x, location.y);
if (behaviour==1)
{
fill(255, 0, 0);
}
else if ( behaviour==0)
{
fill(255, 255, 255);
}
ellipse(0, 0, 4, 4);
strokeWeight(1);
popMatrix();
}
void checkEdges()
{
if (location.x < 0) {
location.x = 0;
velocity.x *= -1;
acceleration.mult(0.001);
}
if (location.x > 800) {
location.x = 800;
velocity.x *= -1;
acceleration.mult(0.001);
}
if (location.y < 0) {
location.y = 0;
velocity.y *= -1;
acceleration.mult(0.001);
}
if (location.y > 800) {
location.y = 800;
velocity.y *= -1;
acceleration.mult(0.001);
}
}
void repel()
{
for (int i=0; i<numAgents; i++) {
if ((agents[i].behaviour==1))
{
int k;
k=1;
for (int j=0; j<numAgents; j++)
{
//--------------
// float dm = agents[i].location.dist(agents[k].location);
float dm = dist(agents[j].location.x, agents[j].location.y, agents[i].location.x, agents[i].location.y);
if (dm < 50) {
agents[i].velocity.mult(-1);
agents[i].acceleration.mult(0.5);
agents[j].velocity.mult(-1);
agents[j].acceleration.mult(0.5);
}
else if (behaviour==0)
{
agents[i].velocity.mult(1);
agents[j].velocity.mult(1);
}
//float dm = dist(agents[i].location.x, agents[i].location.y, agents[j].location.x, agents[j].location.y);
// float dm = agents[i].location.dist(agents[j].location);
// int clr=(int) map (dm,0,100,200,0);
if (dm<180 && dm>100)
{
if ( k<2)
{
//println(dm);
//stroke(255,0,0);
r1 = agents[j].location.x;
r2 = agents[j].location.y;
k=k+1;
}
else
{
//fill(random(255),random(255),random(255),random(0,20));
//stroke(0,50);
// texture(A);
//fill(random(0,255),random(0,255),random(0,255),random(0, 40));
// stroke(140, 50);
fill(random(0, 255), random(0, 255), random(0, 255), random(0, 10));
stroke(140, 50);
beginShape();
tint(255,127);
texture(tex);
vertex(agents[i].location.x, agents[i].location.y,0.0,0.0);//aditional u,v coordinates 0,0 - top left of texture
vertex(r1, r2,1.0,0.0);//top right texture coordinate
vertex(agents[j].location.x, agents[j].location.y,1.0,1.0);//bottom right texture coordinat
endShape(CLOSE);
j=300;
}
}
}
/*void triangulate()
{
fill(random(0, 255), random(0, 255), random(0, 255), random(0, 40));
stroke(140, 50);
for (int i=0; i<numAgents; i++)
{
//gens[i].connect==true)
//if(! agents[i].connect)
if (agents[i].behaviour==1)
{
//println(agents[i]);
int k;
k=1;
for (int j=0; j<numAgents; j++)
{
float dm = dist(agents[i].location.x, agents[i].location.y, agents[j].location.x, agents[j].location.y);
// float dm = agents[i].location.dist(agents[j].location);
// int clr=(int) map (dm,0,100,200,0);
if (dm<180 && dm>100)
{
if ( k<2)
{
//println(dm);
//stroke(255,0,0);
}
}
}
}*/
}
}
}
}
int numMovers= 1;
Mover[]movers= new Mover[numMovers];
class Mover
{
PVector location;
PVector velocity;
PVector acceleration;
float topspeed;
boolean hit = false;
Mover()
{
float spead = 800;
location = new PVector(random(0,spead),random(0,spead));
velocity = new PVector(0,0);
acceleration = new PVector(random(-1,1),random(-1,1));//random initial acceleration
topspeed = 4;
}
void update()
{
// Motion 101! Velocity changes by acceleration. Location changes by velocity.
velocity.add(acceleration);
velocity.limit(topspeed);
location.add(velocity);
}
void display()
{
pushMatrix();
translate(location.x,location.y);
//fill(102,0,155,random(120,160));
//fill(32,225,245,127 + sin(frameCount*.01) * 127);
if(hit) fill(255,10,96,120);
else
fill(3,225,190,random(50,127));
ellipse(0,0,30,30);
noStroke();
popMatrix();
}
void checkEdges()
{
if(location.x < 0){
location.x = 0;
velocity.x *= -1;
acceleration.mult(0.001);
}
if(location.x > 800){
location.x = 800;
velocity.x *= -1;
acceleration.mult(0.001);
}
if(location.y < 0){
location.y = 0;
velocity.y *=- 1;
acceleration.mult(0.001);
}
if(location.y > 800){
location.y = 800;
velocity.y *= -1;
acceleration.mult(0.001);
}
}
}
Alright, so I'm trying to make a quick and dirty platformer engine, and I am having some problems with my collision detection and moving platforms. for one thing the "player" seems to bounce on top of moving platforms ever so slightly, and when he hits the right side errors happen as well. I'll upload a jnlp demo so you can try to find more errors and see whats happening, but here is the source:
import java.awt.Rectangle;
import java.util.Vector;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
public class Platformer extends BasicGame{
boolean keys[];
int ALL_KEYS = 0xFF;
Player player;
Vector<Vector<Thing> > things;
int level = 0;
public Platformer() {
super("You've met with a terrible fate, haven't you?");
}
public void init(GameContainer gc) throws SlickException {
keys = new boolean[ALL_KEYS];
for(int i = 0; i < ALL_KEYS; i++){
keys[i] = false;
}
player = new Player();
things = new Vector<Vector<Thing> >();
Vector<Thing> temp = new Vector<Thing>();
temp.add(new Thing(0, 440, 640, 40, 1));
temp.add(new Thing(200, 300, 240, 50, 1));
temp.add(new Thing(500, 200, 240, 50, 1));
things.add(temp);
}
public void update(GameContainer gc, int delta) throws SlickException{
if(keys[Input.KEY_UP]){
player.velo = player.maxJump;
keys[Input.KEY_UP] = false;
}
if(keys[Input.KEY_DOWN]){
keys[Input.KEY_DOWN] = false;
}
if(keys[Input.KEY_LEFT]){
player.delta -= player.speed;
if(player.delta < -player.maxSpeed)
player.delta = -player.maxSpeed;
}
else if(keys[Input.KEY_RIGHT]){
player.delta += player.speed;
if(player.delta > player.maxSpeed)
player.delta = player.maxSpeed;
}
else{
if(player.delta < -0.5){
player.delta += player.speed;
}
else if(player.delta > 0.5){
player.delta -= player.speed;
}
else if(player.delta > -0.5 && player.delta < 0.5){
player.delta = 0;
}
}
if(player.delta < 0)
player.moveLeft(things.get(level));
else if(player.delta > 0)
player.moveRight(things.get(level));
if(player.velo < 0)
player.moveUp(things.get(level));
else
player.moveDown(things.get(level));
things.get(level).get(1).moveRight(player, things.get(level));
}
public void render(GameContainer gc, Graphics g) throws SlickException{
g.setColor(new Color(0,55,55));
g.fillRect(0, 0, 640, 480);
g.setColor(new Color(255,0,0));
g.fillRect(player.x, player.y, player.width, player.height);
for(int i = 0; i < things.get(level).size(); i++){
if(things.get(level).get(i).type == 1)
g.setColor(new Color(0,100,100));
g.fillRect(things.get(level).get(i).x, things.get(level).get(i).y,things.get(level).get(i).width, things.get(level).get(i).height);
}
}
public void keyPressed(int key, char c) {
keys[key] = true;
}
public void keyReleased(int key, char c) {
keys[key] = false;
}
public static void main(String[] args) throws SlickException{
AppGameContainer app =
new AppGameContainer( new Platformer() );
app.setShowFPS(false);
app.setAlwaysRender(true);
app.setTargetFrameRate(60);
app.setDisplayMode(640, 480, false);
app.start();
}
class Player{
float x = 50;
float y = 50;
float delta = 0; // x momentum
float velo = 0;
int height = 50;
int width = 30;
float speed = 0.2f;
int maxSpeed = 6;
int maxFallSpeed = 5;
int maxJump = -8;
public void moveLeft(Vector<Thing> things){
x += delta;
if(x < 0)
x = 0;
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
x += (things.get(i).x + things.get(i).width) - x;
delta = 0;
}
}
}
public void moveRight(Vector<Thing> things){
x += delta;
if(x + width > 640)
x = (640 - width);
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
x -= (x + width) - things.get(i).x;
delta = 0;
}
}
}
public void moveLeftWithThing(Vector<Thing> things, float thingSpeed){
x -= thingSpeed;
if(x < 0)
x = 0;
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
x += (things.get(i).x + things.get(i).width) - x;
delta = 0;
}
}
}
public void moveRightWithThing(Vector<Thing> things, float thingSpeed){
x += thingSpeed;
if(x + width > 640)
x = (640 - width);
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
x -= (x + width) - things.get(i).x;
delta = 0;
}
}
}
public void moveUp(Vector<Thing> things){
y += velo;
velo += speed;
if(velo > maxFallSpeed)
velo = maxFallSpeed;
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height/2).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
y += (things.get(i).y + things.get(i).height) - y;
velo = 0;
}
}
}
public void moveDown(Vector<Thing> things){
y += velo;
velo += speed;
if(velo > maxFallSpeed)
velo = maxFallSpeed;
boolean b = false;
for(int i = 0; i < things.size(); i++){
if(!b && new Rectangle((int) x, (int) y + (height/2), width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
y -= (y + height) - things.get(i).y;
velo = 0;
}
}
}
}
class Thing{
float x = 50;
float y = 50;
int height = 50;
int width = 30;
int type = -1;
float speed = 0.5f;
public Thing(float x, float y, int width, int height, int type){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.type = type;
}
public void moveUp(Player player){
y -= 0.5f;
if(new Rectangle((int) x,(int) y, width, height).intersects(new Rectangle((int) player.x, (int) player.y, player.width, player.height))){
player.y -= (player.y + player.height) - y;
player.velo = 0;
}
}
public void moveRight(Player player, Vector<Thing> things){
x += speed;
if(new Rectangle((int) x,(int) y - 1, width, height).intersects(new Rectangle((int) player.x, (int) player.y, player.width, player.height))){
player.moveRightWithThing(things, speed);
}
}
}
}
And here is the demo: http://prime.programming-designs.com/java/platformer_demo/platdemo.jnlp
The reason why you are having trouble finding the error is that the code is ghastly.
Vast amounts of duplication of code: moveLeft, moveRight, moveUp and moveDown are all very similar.
Logic for acceleration due to gravity appears in two places.
Collision logic repeated all over the place.
Desperately poor choice of names. velo for velocity downwards, but delta for velocity rightwards (mislabelled as "momentum"): why not vy and vx? Also maxSpeed for maximum horizontal velocity but maxFallSpeed for maximum vertical velocity.
Acceleration/deceleration called speed.
Wasteful allocation, e.g. calling new Rectangle every time you want to test whether something has hit something else.
Positions are floating-point, but collision is based on integers.
Duplication of code has the effect of introducing bugs, because when functionality is duplicated there's the possibility of getting it wrong in one of the places, and also of hiding bugs, because the volume of code makes it harder to spot them.
Anyway, the bouncing on platforms may be something to do with the fact that in Player:moveDown you are using a rectangle that's offset by half the player's height, whereas in Thing:moveRight you are colliding with a rectangle that's not offset. (But that's just a guess.)