I don't really understand where in the code that makes the character bounce to the right side and not countinue.
public void exercise1e() {
PaintWindow pw = new PaintWindow();
Random rand = new Random();
ImageIcon image = new ImageIcon("C:/Users/char.jpg");
int width = pw.getBackgroundWidth();
int height = pw.getBackgroundHeight();
int dx = -2;
int dy = 0;
int x = 250;
int y = rand.nextInt(height-100);
while(true) {
pw.showImage(image, x, y);
PaintWindow.pause(20);
x += dx;
y += dy;
if(x<0) {
dx = -dx;
if (x>0) {
}
}
}
}
If you reach a boundary then change the direction to the opposite, dx=-dx will cause that effect.
Your condition should be applied if reach the left limit.. when x<=0 and also when reached the right limit x>=width
if(x<=0 || x>=width ) {
dx = -dx;
}
Now reset the position of your image to x. Otherwise you are just increasing and decreasing that number.
Something like: image.setLocation(x,y), I can't be sure since I don't know what you are using to render this.
There is a logical contradiction in your current if statements.
if(x<0) {
Only if x is less than 0 evaluate the next if...
if (x>0) {
If x is less than 0 but also is greater than 0, understand the universe.
}
}
Related
I am looking for some help with some game code i have inherited from a flight sim. The code below simulates bombs exploding on the ground, it works fine but i am trying to refine it.
At the moment it takes a random value for x and y as a start point and then adds another random value between -20 and 20 to this. It works ok, but doesn't simulate bombs dropping very well as the pattern does not lay along a straight line/
What i would like to achieve though is all x and y points after the first random values, to lay along a straight line, so that the effects called for all appear to lay in a line. It doesn't matter which way the line is orientated.
Thanks for any help
slipper
public static class BombUnit extends CandCGeneric
{
public boolean danger()
{
Point3d point3d = new Point3d();
pos.getAbs(point3d);
Vector3d vector3d = new Vector3d();
Random random = new Random();
Aircraft aircraft = War.GetNearestEnemyAircraft(this, 10000F, 9);
if(counter > 10)
{
counter = 0;
startpoint.set(point3d.x + (double)(random.nextInt(1000) - 500), point3d.y + (double)(random.nextInt(1000) - 500), point3d.z);
}
if(aircraft != null && (aircraft instanceof TypeBomber) && aircraft.getArmy() != myArmy)
{
World.MaxVisualDistance = 50000F;
counter++;
String s = "weapon.bomb_std";
startpoint.x += random.nextInt(40) - 20;
startpoint.y += random.nextInt(40) - 20;
Explosions.generate(this, startpoint, 7F, 0, 30F, !Mission.isNet());
startpoint.z = World.land().HQ(startpoint.x, startpoint.y);
MsgExplosion.send(this, s, startpoint, getOwner(), 0.0F, 7F, 0, 30F);
Engine.land();
int i = Landscape.getPixelMapT(Engine.land().WORLD2PIXX(startpoint.x), Engine.land().WORLD2PIXY(startpoint.y));
if(firecounter < 100 && i >= 16 && i < 20)
{
Eff3DActor.New(null, null, new Loc(startpoint.x, startpoint.y, startpoint.z + 5D, 0.0F, 90F, 0.0F), 1.0F, "Effects/Smokes/CityFire3.eff", 300F);
firecounter++;
}
super.setTimer(15);
}
return true;
}
private static Point3d startpoint = new Point3d();
private int counter;
private int firecounter;
public BombUnit()
{
counter = 11;
firecounter = 0;
Timer1 = Timer2 = 0.05F;
}
}
The code in the question is a mess, but ignoring this and trying to focus on the relevant parts: You can generate a random position for the first point, and a random direction, and then walk along this direction in several steps.
(This still raises the question of whether the direction is really not important. Wouldn't it matter if only the first bomb was dropped in the "valid" area, and the remaining ones outside of the screen?)
However, the relevant code could roughly look like this:
class Bombs
{
private final Random random = new Random(0);
int getScreenSizeX() { ... }
int getScreenSizeY() { ... }
// Method to drop a single bomb at the given position
void dropBombAt(double x, double y) { ... }
void dropBombs(int numberOfBombs, double distanceBetweenBombs)
{
// Create a random position in the screen
double currentX = random.nextDouble() * getScreenSizeX();
double currentY = random.nextDouble() * getScreenSizeY();
// Create a random step size
double directionX = random.nextDouble();
double directionY = random.nextDouble();
double invLength = 1.0 / Math.hypot(directionX, directionY);
double stepX = directionX * invLength * distanceBetweenBombs;
double stepY = directionY * invLength * distanceBetweenBombs;
// Drop the bombs
for (int i=0; i<numberOfBombs; i++)
{
dropBombAt(currentX, currentY);
currentX += stepX;
currentY += stepY;
}
}
}
I am assuming your startpoint is a StartPoint class with x,y,z coordinates as integers in it.
I hope I have understood your problem correctly. It looks like you either want to create a vertical explosion or a horizontal explosion. Since an explosion always occurs on ground, the z coordinate will be zero. Now you can vary one of x or y coordinate to give you a random explosion along a straight line. Whether you choose x or y could be fixed or could be randomized itself. A potential randomized solution below:
public boolean danger() {
// stuff
int orientation = Random.nextInt(2);
if(aircraft != null && (aircraft instanceof TypeBomber) && aircraft.getArmy() != myArmy)
{
// stuff
startPoint = randomizeStartPoint(orientation, startPoint);
// stuff
}
}
StartPoint randomizeStartPoint(int orientation, StartPoint startPoint) {
if(orientation == 0) {
startPoint.x += random.nextInt(40) - 20;
}
else {
startPoint.y += random.nextInt(40) - 20;
}
return startPoint;
}
In response to the image you uploaded, it seems that the orientation of the explosion need not necessarily be horizontal or vertical. So the code I posted above gives a limited solution to your problem.
Since you want any random straight line, your problem boils down to two sub parts:
1. Generate a random straight line equation.
2. Generate random point along this line.
Now, a straight line equation in coordinate geometry is y = mx + c where m is the slope and c is the constant where the line crosses the y-axis. The problem with c is that it gives rise to irrational coordinates. I am assuming you are looking for integer coordinates only, since this will ensure that your points are accurately plotted. (You could do with rational fractions, but then a fraction like 1/3 will still result in loss of accuracy). The best way to get rid of this irrational problem is to get rid of c. So now your straight line always looks like y = mx. So for step one, you have to generate a random m.
Then for step 2, you can either generate a random x or random y. It doesn't matter which one, since either one will result in random coordinates.
Here is a possible code for the solution:
int generateRandomSlope() {
return Random.nextInt(100); // arbitrarily chose 100.
}
int randomizeStartPoint(int m, StartPoint startPoint) { // takes the slope we generated earlier. without the slope, your points will never be on a straight line!
startPoint.x += random.nextInt(40) - 20;
startPoint.y += x * m; // because a line equation is y = mx
return startPoint;
}
public boolean danger() {
// stuff
int m = generateRandomSlope(); // you may want to generate this elsewhere so that it doesn't change each time danger() is called.
if(aircraft != null && (aircraft instanceof TypeBomber) && aircraft.getArmy() != myArmy)
{
// stuff
startPoint = randomizeStartPoint(m, startPoint);
// stuff
}
}
Again, this is not a complete or the best solution.
i have a program that generates a random maze. In the maze a red dot is displayed and the red dot flashes on by each block in the maze. all the blocks in the maze are == 1 and if the red dot goes through that block, it increments ++. the red dot goes in the direction towards the lowest number, that way it wont stay in an infinite loop by a dead end. once it reaches the end, ive solved the maze.
This is where im stumped, im trying to print the red dot to find the optimal route all the way back to the beginning where it started. I used a stack class that i made to record all the y and x components of where the red dot traveled. im able to traceback every where the red dot has gone but that isnt the optimal solution.
My question is how could i print the red dot tracing back in only the optimal path. My idea of solving this would be to check and see if the coordinates of a stack where visited before, if so..find the last case where it was visited and print the red dot up until that point. that way itll never deal with the dead ends it traveled.
the method solve() is what contains the traceback and solving technique for the red dot to travel through the maze and back.
Im not the greatest programmer and im still learning how to use stacks, ive been stumped for hours and dont know how to approach this. Please be kind and explain how you would do it using the stack i made. Thank you
import java.awt.*;
import java.awt.event.*;
import java.awt.Graphics;
import javax.swing.*;
public class mazedfs extends JFrame implements KeyListener
{
/* default values: */
private static int bh = 16; // height of a graphical block
private static int bw = 16; // width of a graphical block
private int mh = 41; // height and width of maze
private int mw = 51;
private int ah, aw; // height and width of graphical maze
private int yoff = 40; // init y-cord of maze
private Graphics g;
private int dtime = 40; // 40 ms delay time
byte[][] M; // the array for the maze
public static final int SOUTH = 0;
public static final int EAST = 1;
public static final int NORTH = 2;
public static final int WEST = 3;
public static boolean showvalue = true; // affects drawblock
// args determine block size, maze height, and maze width
public mazedfs(int bh0, int mh0, int mw0)
{
bh = bw = bh0; mh = mh0; mw = mw0;
ah = bh*mh;
aw = bw*mw;
M = new byte[mh][mw]; // initialize maze (all 0's - walls).
this.setBounds(0,0,aw+10,10+ah+yoff);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try{Thread.sleep(500);} catch(Exception e) {} // Synch with system
this.addKeyListener(this);
g = getGraphics(); //g.setColor(Color.red);
setup();
}
public void paint(Graphics g) {} // override automatic repaint
public void setup()
{
g.setColor(Color.green);
g.fill3DRect(0,yoff,aw,ah,true); // fill raised rectangle
g.setColor(Color.black);
// showStatus("Generating maze...");
digout(mh-2,mw-2); // start digging!
// digout exit
M[mh-1][mw-2] = M[mh-2][mw-1] = 1;
drawblock(mh-2,mw-1);
solve(); // this is the function you will write for parts 1 and 2
play(); // for part 3
}
public static void main(String[] args)
{
int blocksize = bh, mheight = 41, mwidth = 41; // need to be odd
if (args.length==3)
{
mheight=Integer.parseInt(args[0]);
mwidth=Integer.parseInt(args[1]);
blocksize=Integer.parseInt(args[2]);
}
mazedfs W = new mazedfs(blocksize,mheight,mwidth);
}
public void drawblock(int y, int x)
{
g.setColor(Color.black);
g.fillRect(x*bw,yoff+(y*bh),bw,bh);
g.setColor(Color.yellow);
// following line displays value of M[y][x] in the graphical maze:
if (showvalue)
g.drawString(""+M[y][x],(x*bw)+(bw/2-4),yoff+(y*bh)+(bh/2+6));
}
void drawdot(int y, int x)
{
g.setColor(Color.red);
g.fillOval(x*bw,yoff+(y*bh),bw,bh);
try{Thread.sleep(dtime);} catch(Exception e) {}
}
/////////////////////////////////////////////////////////////////////
/* function to generate random maze */
public void digout(int y, int x)
{
M[y][x] = 1; // digout maze at coordinate y,x
drawblock(y,x); // change graphical display to reflect space dug out
int dir = (int)(Math.random()*4);
for (int i=0;i<4;i++){
int [] DX = {0,0,2,-2};
int [] DY = {-2,2,0,0};
int newx = x + DX[dir];
int newy = y + DY[dir];
if(newx>=0 && newx<mw && newy>=0 && newy<mh && M[newy][newx]==0)
{
M[y+DY[dir]/2][x+DX[dir]/2] = 1;
drawblock(y+DY[dir]/2,x+DX[dir]/2);
digout(newy,newx);
}
dir = (dir + 1)%4;}
} // digout
/* Write a routine to solve the maze.
Start at coordinates x=1, y=1, and stop at coordinates
x=mw-1, y=mh-2. This coordinate was especially dug out
after the program called your digout function (in the "actionPerformed"
method).
*/
public void solve()
{
int x=1, y=1;
Stack yourstack = null;
drawdot(y,x);
while(y!=mh-2 || x!=mw-2 && M[y][x]!=0){
int min = 0x7fffffff;
int DX = 0;
int DY = 0;
if (y-1>0 && min>M[y-1][x] && M[y-1][x]!=0){
min = M[y-1][x];
DX = 0;
DY = -1;
}//ifNORTH
if (y+1>0 && min>M[y+1][x] && M[y+1][x]!=0){
min = M[y+1][x];
DY = 1;
DX = 0;
}//ifSOUTH
if (x-1>0 && min>M[y][x-1] && M[y][x-1]!=0){
min = M[y][x-1];
DX = -1;
DY = 0;
}//ifWEST
if (x+1>0 && min>M[y][x+1] && M[y][x+1]!=0){
min = M[y][x+1];
DX = 1;
DY = 0;
}//ifEAST
M[y][x]++;
drawblock(y,x);
x = x+DX;
y = y+DY;
drawdot(y,x);
yourstack = new Stack(y,x,yourstack); // creates new stack for each coordinate travelled
}//while
while(yourstack != null){
yourstack = yourstack.tail;
drawdot(yourstack.y,yourstack.x); // this will traceback every box ive been through
}//while
} // solve
class Stack{
int x;
int y;
Stack tail;
public Stack(int a, int b, Stack t){
y = a;
x=b;
tail=t;
}
}//stackclass
///////////////////////////////////////////////////////////////
/// For part three (save a copy of part 2 version first!), you
// need to implement the KeyListener interface.
public void play() // for part 3
{
// code to setup game
}
// for part 3 you may also define some other instance vars outside of
// the play function.
// for KeyListener interface
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) // change this one
{
int key = e.getKeyCode(); // code for key pressed
System.out.println("YOU JUST PRESSED KEY "+key);
}
} // mazedfs
////////////
// define additional classes (stack) you may need here.
when you trace your path back you currently just go back to your stack - but thats not the shortest path...
...whenever you can go back check the values of M around you:
byte valueOfFieldNorthOfXY = M[x][y-1]; //x/y is your current position
byte valueOfFieldWesthOfXY = M[x-1][y];
byte ...;
byte ...; //and so on...
while the first while-loop in your solve-methode simplay solves the maze by flooding it the second while-method is for going back...
and when i say flooding i mean: each time a field has been passed by the 'walker' the value of M[x][y] has been increased by 1 (when the 'walker' has walked 3x over field 5/6 then the value from M[5][6] = 3)
so when you go back from the end (#40/50) to the start (#1/1), you do this algorith:
1) i stand on x/y
2) i check the values north/east/south/west of me
2a) if i come from north, then i ignore the north field
2 ) ... and so on...
2d) if i come from west , then i ignore the west field
3) i pick that direction, where the value is the least
4) put the current field int your packPathStack and walk to
the 'best' direction
5) repeat (go back to Nr.1) until you are #1/1
example
? 4 ? //i'm standing at X (x/y)
2 x f //? are values from walls or not yet considerd
? ? ? //f is where i come from
--> i pick direction WEST(2) because thats less than NORTH(4)
implement this algorithm and you a NEW stack i call it yourPathBackStack
Stack yourPathBackStack = new Stack();
while(x != 1 && y != 1 ){ //x/y = 1/1 = start - do it until you are there (Nr. 5)
// 1) i stand on x/y
int x = yourPathBackStack.x;
int y = yourPathBackStack.y;
// 2) i check the values north/east/south/west of me
byte valueOfFieldNorthOfXY = ... ; //as seen above
// 2a) if i come from north, then i ignore the north field
if (yourstack.tail.x == x && yourstack.tail.y == y-1){
//check - i DO come from north
//make then valueOfFieldNorthOfXY very high
valueOfFieldNorthOfXY = 100; //it's the same as ignoring
}
// 2 ) ... and so on...
// 2d) if i come from west , then i ignore the west field
if (yourstack.tail.x == x-1 && ...// as seen above
// 3) i pick that direction, where the value is the least
int direction = NORTH; //lets simply start with north;
byte maxValue = 100;
if ( valueOfFieldNorthOfXY < maxValue ){ //First north
maxValue = valueOfFieldNorthOfXY;
direction = NORTH;
}
if ( valueOfFieldWestOfXY < maxValue ){ //Then east
maxValue = valueOfFieldWestOfXY ;
direction = WEST;
}
//then the also other directions
if ( value ... //as seen above
// 4) put the current field int your yourPathBackStack and walk to
// the 'best' direction
int newx = x;
int newy = y;
if (direction == NORTH){ //direction has been caclulated above
newy = newy - 1;
}
if (direc ... //with all other direction)
yourPathBackStack = new Stack(newx, newy, yourPathBackStack );
drawdot(yourPathBackStack.y,yourPathBackStack.x);
}
So I made a java game with jumping some time ago and I used this method for all the moving:
double height = 0, speed = 4;
public static final double gravity = 9.81;
double x = 25;
int a;
int y = (int) (500-(height*100));
boolean left = false, right = false, up = false;
public void the_jump() {
long previous = 0, start = 0;
while(true){
start = System.nanoTime();
if(previous != 0 && up){
double delta = start - previous;
height = (height + (delta/1000000000) * speed);
speed -= (delta/1000000000) * gravity;
y = (int) (500-(height * 100));
}
if(left){
x-= 3;
}
if(right){
x+= 3;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(height < 0){
height = 0;
speed = 4;
up = false;
}
previous = start;
}
}
Now It was okay when I did it all with just JComponents and such, but now when I want to implement it in a Slick enviroment, it fails.
The problem is in the while(true){} loop. If I change it against for(int i = 0; i < 1; i++) loop, then moving left and right will work. But this will not work for the jumping. I could increase the i < 1 to i < 5 and then the jump will work, but at the cost of a lot of performance.
So how would people implement this in slick? Right now I am calling the the_jump(); out in my public void update(GameContainer gc, int t) throws SlickException method, and if I use the while loop, the game will crash.
Slick already loop on update(GameContainer gc, int delta), you have to put all the code located in your while loop into the update method.
Moreover, you get the delta time between two update as parameter, and so not have to calculate it.
Feel free to ask me more question ;)
Off Topic, do you know if Slick2d is still maintain ? I switch to libGDX a few month ago, and I really advice you to test it, it's soooo fun :)
So I understand that I'm not coding this the best way possible at the moment; this is a sort of test run. What I'm trying to do is wall collisions using rectangles and the intersects property (sorry if I'm not using the correct terminology). So far I have 2 rectangles on screen. 1 the player controls and the other which the play is colliding with. When they collide the player stops moving. The problem is that if the player is trying to move into the rectangle while they are already colliding then the player can't move in any direction perpendicular to the movement ie if the player is holding the right arrow key moving into the rectangle, then they cannot move up or down. The game works on the premise that if your x or y coordinates aren't valid, then you will be moved back to the last valid coordinate recorded but I'm having trouble detecting the valid x and y coordinate separately. Here is the code:
public void Collision()
{
if(x < 0)
x = 0;
if(x > 400 - width)
x = 400 - width;
if(y < 0)
y = 0;
if(y > 300 - height)
y = 300 - height;
rect1 = new Rectangle(x, y, 16, 16);
rect2 = new Rectangle(sx, sy, wid, hei);
if(!rect1.intersects(rect2))
{
validX = true;
validY = true;
}
else
{
validX = false;
validY = false;
}
if(validX)
{
lastValidX = x;
}
if(validY)
{
lastValidY = y;
}
if(!validX)
{
x = lastValidX;
}
if(!validY)
{
y = lastValidY;
}
}
The Collision() method in the Guy class is where I'm having the trouble I believe. Yes my code is pretty messy right now but this is only a test.
Thanks, David.
You can implement what you're describing by doing extra logic around here (i.e. detecting cases when one is false and the other is true):
if(!rect1.intersects(rect2))
{
validX = true;
validY = true;
}
else
{
validX = false;
validY = false;
}
However, it seems like maybe you shouldn't be allowing the rectangles to ever be in a "colliding" state in the first place. For example, you can change the Move method to do something like
public void Move()
{
int oldX = x, oldY = y;
x += dx;
y += dy;
if (Collision()) {
x = oldX;
y = oldY;
}
}
I have a number of rectangles, and am trying to generate a random point that is not inside any of them. I created a method to do this, but it appears that this is causing my application to freeze because it has to go through a large number of points before a valid point is generated:
public Point getLegalPoint() {
Random generator = new Random();
Point point;
boolean okPoint = true;
do {
point = new Point(generator.nextInt(975), generator.nextInt(650));
for (int i = 0; i < buildingViews.size(); i++) {
if (buildingViews.get(i).getBuilding().getRectangle()
.contains(point)) {
okPoint = false;
break;
}
}
} while (okPoint == false);
return point;
}
Is there something I am doing wrong, or is there a more efficient way to do it so that it won't freeze my application?
This code results to infinite loop if you don't succeed on the first try, okPoint = true must be inside the do block. See what your performance is when you fix that.
I cannot think of a faster way as you check against multiple rectangles and not just one.
Generate a random point. Then check if it is inside bounds of rectangle. if it is then:
Let centerX and centerY be the x and y of the center point of rectangle.
if randPointX < centerX then let randPointX = randPointX - centerX
if randPointX > centerX then let randPointX = randPointX + centerX
Do same for y ordinate
you will need to do bounds checking again to see if the point is outside the larger view (screen i'm assuming). Just warp coordinates. so if randPointX is negative then let it equal max_X + randPointX
I would try something like this:
select whether the point is above/below/on left side/on right side of rectange (nextInt(4)) and then select random point in this area
code:
public Point getLegalPoint(int x, int y, int width, int height){
Random generator = new Random();
int position = generator.nextInt(4); //0: top; 1: right; 2: bottom; 3:right
if (position == 0){
return new Point(generator.nextInt(975),y-generator.nextInt(y);
} else if (position == 2){
return new Point(generator.nextInt(975),y+height+(generator.nextInt(650-(y+height)));
}
... same for x ...
}