I'm trying to make a 2D game. I have an array of rectangles to represent attacks. I am trying to make them rotate so they are all rotated 45 degrees. When I try rendering more spells after the first, they glitch to random places around the screen. Here is my code:
Rectangle[] waterBolt = new Rectangle[10];
float[] wba = new float[10];
int wbc = 0;
Graphics2D[] gwb = new Graphics2D[10];
public void renderSpell(Graphics2D g) {
for(int i=0; i<10; i++) {
if (waterBolt[i] != null) {
gwb[i] = (Graphics2D) g;
gwb[i].rotate(Math.toRadian(45), waterBolt[i].x, waterBolt[i].y);
gwb[i].fill(waterBolt[i]);
}
}
}
public void castSpell(int spellID) {
waterBolt[wbc] = new Rectangle(playerX, playerY, 16, 16);
wba[wbc] = (float) Math.toRadians(Math.atan2(mouseX - playerX, mouseY - playerY));
wbc++;
if (wbc >= 10) {
wbc = 0;
}
}
And here is what is happening to my screen when I cast them all standing still:
They all rotate 45 more degrees every time I click to cast, but I don't know how to fix it.
Keep in mind that when you call gwb[i] = (Graphics2D) g;, you are not making a copy of g. Instead, each of your rectangles is being rotated by the cumulative sum of all of your previous rotations. Try something like this instead:
public void renderSpell(Graphics2D g) {
AffineTransform transform = g.getTransform();
for(int i=0; i<waterBolt.length; i++) {
if (waterBolt[i] != null) {
g.rotate(Math.toRadian(45), waterBolt[i].x, waterBolt[i].y);
g.fill(waterBolt[i]);
g.setTransform(transform); // back to original orientation
}
}
}
Related
I was steered over to this forum when I asked my lecturer for advice on a piece of code for a group project. The general idea is that there are two images on top of each other, the user can wipe the top image away to reveal the one underneath.
Using some other projects from this forum, I have managed to get the basics running, however I am struggling to get the code to the starting point once the user lets go of the mouse.
I would also appreciate any advice regarding how to convert this to using a touch screen. I have looked at the multitouch code within the processing app, however it does not allow me to add images to this, and if I try and use the computer software it does not seem to like the multitouch. Is there any way around this?
The code I currently have is below, I will be greatful so any advice or input- thanks in advance!
PImage img, front;
int xstart, ystart, xend, yend;
int ray;
void setup()
{
size(961, 534);
img = loadImage("back.jpg");
front = loadImage("front.jpg");
xstart = 0;
ystart = 0;
xend = img.width;
yend = img.height;
ray = 50;
}
void draw()
{
{
img.loadPixels();
front.loadPixels();
// loop over image pixels
for (int x = xstart; x < xend; x++)
{
for (int y = ystart; y < yend; y++ )
{
int loc = x + y*img.width;
float dd = dist(mouseX, mouseY, x, y);
// pixels distance less than ray
if (mousePressed && dd < 50)
{
// set equal pixel
front.pixels[loc] = img.pixels[loc];
}
else
{
if (!mousePressed)
{
// reset- this is what I have not been able to work as of yet
front.pixels[loc] = ;
}
}
}
}
img.updatePixels();
front.updatePixels();
// show front image
image(front, 0, 0);
}
}
I recommend to use a mask instead of changing the pixels of the image. Create an empty image and associated it as mask to the the image:
img = loadImage("back.jpg");
front = loadImage("front.jpg");
mask = createImage(img.width, img.height, RGB);
img.mask(mask);
If you now draw both images, then you can only "see" the front image:
image(front, 0, 0);
image(img, 0, 0);
Set the color of the mask (255, 255, 255) instead of changing the pixel of front:
mask.pixels[loc] = color(255, 255, 255);
and reapply the mask to the image
img.mask(mask);
When the mouse button is released, the pixels of the mask have to be changed back to (0, 0, 0) or simply create a new and empty mask:
mask = createImage(img.width, img.height, RGB);
See the example where I applied the suggestions to your original code:
PImage img, front, mask;
int xstart, ystart, xend, yend;
int ray;
void setup() {
size(961, 534);
img = loadImage("back.jpg");
front = loadImage("front.jpg");
mask = createImage(img.width, img.height, RGB);
img.mask(mask);
xstart = 0;
ystart = 0;
xend = img.width;
yend = img.height;
ray = 50;
}
void draw() {
img.loadPixels();
front.loadPixels();
// loop over image pixels
for (int x = xstart; x < xend; x++) {
for (int y = ystart; y < yend; y++ ) {
int loc = x + y*img.width;
float dd = dist(mouseX, mouseY, x, y);
if (mousePressed && dd < 50) {
mask.pixels[loc] = color(255, 255, 255);
}
else {
if (!mousePressed) {
//mask = createImage(img.width, img.height, RGB);
mask.pixels[loc] = color(0, 0, 0);
}
}
}
}
mask.updatePixels();
img.mask(mask);
// show front image
image(front, 0, 0);
image(img, 0, 0);
}
I am using Processing in Java to perpetually draw a line graph. This requires a clearing rectangle to draw over drawn lines to make room for the new part of the graph. Everything works fine, but when I call a method, the clearing stops working as it did before. Basically the clearing works by drawing a rectangle in front of where the line is currently at
Below are the two main methods involved. The drawGraph function works fine until I call the redrawGraph which redraws the graph based on the zoom. I think the center variable is the cause of the problem but I cannot figure out why.
public void drawGraph()
{
checkZoom();
int currentValue = seismograph.getCurrentValue();
int lastValue = seismograph.getLastValue();
step = step + zoom;
if(step>offset){
if(restartDraw == true)
{
drawOnGraphics(step-zoom, lastY2, step, currentValue);
image(graphGraphics, 0, 0);
restartDraw = false;
}else{
drawOnGraphics(step-zoom, lastValue, step, currentValue);
image(graphGraphics, 0, 0);
}
} // draw graph (connect last to current point // increase step - x axis
float xClear = step+10; // being clearing area in front of current graph
if (xClear>width - 231) {
xClear = offset - 10; // adjust for far side of the screen
}
graphGraphics.beginDraw();
if (step>graphSizeX+offset) { // draw two clearing rectangles when graph isn't split
// left = bg.get(0, 0, Math.round(step-graphSizeX), height - 200); // capture clearing rectangle from the left side of the background image
// graphGraphics.image(left, 0, 0); // print left clearing rectangle
// if (step+10<width) {
// right = bg.get(Math.round(step+10), 0, width, height - 200); // capture clearing rectangle from the right side of the background image
// // print right clearing rectangle
// }
} else { // draw one clearing rectangle when graph is split
center = bg.get(Math.round(xClear), lastY2, offset, height - 200); // capture clearing rectangle from the center of the background image
graphGraphics.image(center, xClear - 5, 0);// print center clearing rectangle
}
if (step > graphSizeX+offset) { // reset set when graph reaches the end
step = 0+offset;
}
graphGraphics.endDraw();
image(graphGraphics, 0 , 0);
System.out.println("step: " + step + " zoom: " + zoom + " currentValue: "+ currentValue + " lastValue: " + lastValue);
}
private void redrawGraph() //resizes graph when zooming
{
checkZoom();
Object[] data = seismograph.theData.toArray();
clearGraph();
step = offset;
int y2, y1 = 0;
int zoomSize = (int)((width - offset) / zoom);
int tempCount = 0;
graphGraphics.beginDraw();
graphGraphics.strokeWeight(2); // line thickness
graphGraphics.stroke(242,100,66);
graphGraphics.smooth();
while(tempCount < data.length)
{
try
{
y2 = (int)data[tempCount];
step = step + zoom;
if(step > offset && y1 > 0 && step < graphSizeX+offset){
graphGraphics.line(step-zoom, y1, step, y2);
}
y1 = y2;
tempCount++;
lastY2 = y2;
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
graphGraphics.endDraw();
image(graphGraphics, 0, 0);
restartDraw = true;
}
Any help and criticisms are welcome. Thank you for your valuable time.
I'm not sure if that approach is the best. You can try something as simple as this:
// Learning Processing
// Daniel Shiffman
// http://www.learningprocessing.com
// Example: a graph of random numbers
float[] vals;
void setup() {
size(400,200);
smooth();
// An array of random values
vals = new float[width];
for (int i = 0; i < vals.length; i++) {
vals[i] = random(height);
}
}
void draw() {
background(255);
// Draw lines connecting all points
for (int i = 0; i < vals.length-1; i++) {
stroke(0);
strokeWeight(2);
line(i,vals[i],i+1,vals[i+1]);
}
// Slide everything down in the array
for (int i = 0; i < vals.length-1; i++) {
vals[i] = vals[i+1];
}
// Add a new random value
vals[vals.length-1] = random(height);//use seismograph.getCurrentValue(); here instead
}
You can easily do the same using a PGraphics buffer as your code suggests:
// Learning Processing
// Daniel Shiffman
// http://www.learningprocessing.com
// Example: a graph of random numbers
float[] vals;
PGraphics graph;
void setup() {
size(400,200);
graph = createGraphics(width,height);
// An array of random values
vals = new float[width];
for (int i = 0; i < vals.length; i++) {
vals[i] = random(height);
}
}
void draw() {
graph.beginDraw();
graph.background(255);
// Draw lines connecting all points
for (int i = 0; i < vals.length-1; i++) {
graph.stroke(0);
graph.strokeWeight(2);
graph.line(i,vals[i],i+1,vals[i+1]);
}
graph.endDraw();
image(graph,0,0);
// Slide everything down in the array
for (int i = 0; i < vals.length-1; i++) {
vals[i] = vals[i+1];
}
// Add a new random value
vals[vals.length-1] = random(height);//use seismograph.getCurrentValue(); here instead
}
The main idea is to cycle the newest data in an array and simply draw the values from this shifting array. As long as you clear the previous frame (background()) the graph should look ok.
I am trying to figure out why is my Array not showing any lines, I am trying to make it draw 10 different lines, now println of x and z does show 10 coordinates but they are identical and it seems as if they are being passed down to the object line itself but not drawn. It seems quite simple but I know I've made a mistake somewhere but not sure where.
lines[] mylinesArray = new lines[10];
void setup() {
size(1028, 768, P3D);
translate(width/2, height/2, 0);
rotateX(radians(180));
float prp = -2000;
float vrp = 50;
float z = random(prp, 2000);
float x = random(vrp, 500);
for (int i = 0; i<mylinesArray.length; i++) {
mylinesArray[i] = new lines(z, 0, x);
println(z);
println(x);
}
}
void draw() {
background(255);
for (int i=0; i<mylinesArray.length; i++) {
// println(i);
mylinesArray[i].drawlines();
//println("still doing it");
}
}
class lines {
color fillColor;
color strokeColor;
PVector dot1;
PVector dot2;
lines(float xpos, float ypos, float zpos) {
dot1 = new PVector(500+xpos, 200, 700+zpos);
dot2 = new PVector(500+xpos, -400, 700+zpos);
fillColor = strokeColor = color(random(255), random(255), random(255));
}
void drawlines() {
pushMatrix();
line (dot1.x, dot1.y, dot1.z, dot2.x, dot2.y, dot2.z);
stroke(0);
// println("new");
popMatrix();
}
void whatever() {
// println("please");
}
}
I am having a big problem trying to figure out how to use a variable in one overridden method, and also use it in another. Specifically, I am using libgdx, and want to use the variable map in the create method in the render method.
Here is my code:
#Override
public void create() {
batch = new SpriteBatch();
background = new TextureAtlas(
Gdx.files.internal("data/background/background.pack"),
Gdx.files.internal("data/background/"));
bg = background.findRegion("Background");
t = TMXLoader.readTMX("data/world/World.tmx");
ArrayList<Image> map = TMXLoader.drawMap();
camera = new OrthographicCamera(WIDTH, HEIGHT);
camera.position.set(WIDTH / 2, HEIGHT / 2, 0);
camera.update();
}
#Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
BufferedImage image = new BufferedImage(20, 20,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
batch.begin();
for (int i = 0; i < WIDTH; i += bg.getRegionWidth()) {
for (int j = 0; j < HEIGHT; j += bg.getRegionHeight()) {
batch.draw(bg, i, j);
}
}
for (int x = 0; x < t.width; x++) {
for (int y = 0; y < t.height; y++) {
for (Image tile : map) {
float[] scale = getScale();
Image scaledTile = tile.getScaledInstance(
(int) (t.tilewidth * scale[0]),
(int) (t.tileheight * scale[1]), Image.SCALE_FAST);
g2d.drawImage(scaledTile, x, y, null);
}
}
}
batch.end();
}
As it is, I can't access map in the render method. I can't create my own method, because it would have to be called in each method create and render. I am stuck, and can't figure it out on my own. I have a feeling I could use a get/set to do this, but I'm not quite sure how I'd try to do that...
Declare map as a global variable.
private ArrayList<Image> map;
Inside create method, do the assignment as you did-
map = TMXLoader.drawMap();
Now in render method, you can use the map.
I am currently making a collision detection in java, I have a two objects coming from a different class which is a bird and a worm. The worm moves in a random direction while the bird move only when I want him to move because I'm the one who's controlling him by using key arrow buttons. Now, if the two objects collide I want only the worm to be vanish and the bird will remain there. Could somebody help me how to do that? Thanks in advance for sharing your ideas.
This codes is coming from my World class.
public void render()
{
setupStrategy();
x0_pixel = 0;
y0_pixel = 0;
x1_pixel = getWidth();
y1_pixel = getHeight();
x1_world = x1_pixel / meter;
y1_world = y1_pixel / meter;
Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
g2d.setBackground(Color.lightGray);
g2d.clearRect(0, 0, x1_pixel, y1_pixel);
g2d.setColor(Color.BLACK);
for (double x = 0; x < x1_world; x++)
{
for (double y = 0; y < y1_world; y++)
{
int xx = convertToPixelX(x);
int yy = convertToPixelY(y);
g2d.drawOval(xx, yy, 2, 2);
}
}
for (Worm worm : worms)
{
for (Sprite bird : birds)
{
if (!collides())
{
bird.render(g2d);
worm.render(g2d);
}
}
}
g2d.dispose();
strategy.show();
Toolkit.getDefaultToolkit().
sync();
}
public void start() throws InterruptedException
{
long prevLoopStart = System.nanoTime();
Avg avg = new Avg();
while (true)
{
final long loopStart = System.nanoTime();
final long dt = loopStart - prevLoopStart;
for (Worm worm : worms)
{
worm.move(dt);
}
for (Bird bird : birds)
{
bird.move(dt);
}
render();
Collides();
frame.onFpsUpdated(1.0 / dt * SECOND, avg.add(loopStart));
final long elapsed_ns = System.nanoTime() - loopStart;
long expected_elapsed_ms = 1000 / 60;
long elapsed_ms = (long) (elapsed_ns / (1000.0 * 1000.0));
long sleep_ms = expected_elapsed_ms - elapsed_ms;
if (sleep_ms > 0)
{
Thread.sleep(sleep_ms /* ms */);
}
prevLoopStart = loopStart;
}
}
private boolean Collides()
{
ArrayList<Sprite> toDisappear = new ArrayList<Sprite>();
for (int i = 0; i < worms.size(); i++)
{
Sprite r1 = worms.get(i);
for (int j = i + 1; j < birds.size(); j++)
{
Sprite r2 = birds.get(j);
if (r1 == r2)
{
continue;
}
Rectangle me = r1.getBounds();
Rectangle him = r2.getBounds();
if (me.intersects(him))
{
collision = true;
toDisappear.add(r1);
toDisappear.add(r2);
}
toDisappear.remove(r1);
todisappear.remove(r2);
}
}
return collision;
}
This book provides a lot of INFO regarding "Collision Detection" ( Read Chapter 2 and 3 ) and other topics related to Game programming in Java.
http://fivedots.coe.psu.ac.th/~ad/jg/
There are open source frameworks that already do that. If you are doing it for learning purposes then just check their code.
One is Genuts and it SpriteCollisionManager.
The resource that #Upul mention is also of great value.
Regards.
you have a nested for-loop which checks for collisions between birds and worms. if there is a collision neither of them are drawn. Your code also incorrectly draws birds and worms multiple times.
for (Worm worm : worms){
for (Sprite bird : birds){
if (!collides()){
bird.render(g2d);
worm.render(g2d);
}
}
}
The correct way to go is to remove the worm from the list when there is a collision:
for (Iterator<Worm> wit = worms.getIterator(); wit.hasNext(); ){
Worm worm = wit.next();
for (Sprite bird : birds){
if (worm.collidesWith(bird)){
wit.remove();
break;
}
}
}
for (Worm worm : worms){
worm.render(g2d);
}
for (Sprite bird : birds){
bird.render(g2d);
}
Now I assume that you will implement a boolean collidesWith(Bird other) method in class worm so that you can compare that specific worm with the bird you got as an argument. Alternatively make a function as such:
boolean collidesWormBird(Sprite worm, Sprite bird){
Rectangle me = worm.getBounds();
Rectangle him = bird.getBounds();
return me.intersects(him);
}