Random directions - java

Hello I am busy with learning Java and I am busy creating a pacman game but now I need to let the ghosts move in a "Random" direction and so now and then this direction has to change vertically/horizontally and vica versa
at the moment the ghost goes from left to right and right to left. the code that is responsible for this action is as follows: (ignore pacman drawing part see below //ghost movement)
DrawPacMan pacman = new DrawPacMan();
DrawGhost ghost = new DrawGhost();
int g1x = 0;
boolean g1r = true;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// pacman movement
diameter = 25;
pacman.drawPacMan(g, getHorPlaats(), getVerPlaats(), diameter, getView(), Color.yellow);
// ghosts movement
g1x += ghostSpeed * (g1r? 1 : -1);
// check direction
if (g1x >= 500) { g1x = 500; g1r = false; }
else if (g1x <= 0) { g1x = 0; g1r = true; }
ghost.drawGhost(g, g1x, 40, diameter, Color.red);
}
Now I don't know how to create a random direction or what functions to use. Can someone give me some hints/help and if possible a little example that I can work further with? and if you want to see more code or something please ask and i'll post :)

Try this:
g1x += ghostSpeed * (Math.random() > 0.5? 1 : -1);
or even simpler:
g1x += ghostSpeed * Math.signum(Math.random() - 0.5);
This exploits the fact that Math.random() returns uniformly distributed value in [0, 1).
But you'll quickly realize that such an algorithm will cause ghosts to move erratically, from left to right. You'll need something more elegant. E.g. if ghost moves to left, let him continue with 75% probability or change the direction with 25% of probability. I'll let you tackle this.

For something simple like this, I'd generate a random number, either 0, 1, 2, or 3. This will give you all the directions you need: up, down, left, and right.
import java.util.Random;
// create a random number generator
Random randomGen = new Random();
// generate a random number, between 0 and n-1 (0,1,2,3 in this case)
int theRandomNumber = randomGen.nextInt(4);
public void setRandomGhostDirection() {
switch(theRandomNumber) {
case 0:
moveUp();
break;
case 1:
moveLeft();
break;
case 2:
moveRight();
break;
case 3:
moveDown();
break;
}
}
You could clean this up by defining the direction numbers as something like
final int DIRECTION_UP = 0 etc.

Math.random() is the function that you're looking for. By itself, this function generates a random double from 0 to 1.
Pseudocode:
double randomDirection = Math.random();
if (direction > 0.25) {
// move left if possible
} else if (direction > 0.5) {
// move right if possible
} else if (direction > 0.75) {
// move down if possible
} else {
// move up if possible
}

Related

Make my rectangle randomly fall down from my screen?

I am trying to make a game and am almost done with the code. But I can't make my rectangle randomly fall down from my screen.
I am coding a car game that is supposed to dodge the other cars. But is not working. can someone help me?
int carx = 200;
int cary = 0;
float speedx = 0;
float speedy = 0;
float accy = 0.1;
color rod = color(255, 0, 0);
color vit = color(255);
final int START_STATE = 1;
final int PLAY_STATE = 2;
final int GAMEOVER_STATE = 3;
final int RESTART = 4;
int state = START_STATE;
void setup() {
size(400, 700);
}
void draw() {
switch (state) {
case START_STATE:
drawStart();
break;
case PLAY_STATE:
drawPlay();
break;
case GAMEOVER_STATE:
drawGameOver();
case RESTART:
drawrestart();
}
}
void init() {
carx = 200;
cary = 0;
speedx = 0;
speedy = 0;
accy = 0.1;
}
void drawStart() {
background(0);
textAlign(CENTER, CENTER);
textSize(16);
text("Click the mouse button to start the game", width / 2, height / 2);
if (mousePressed) {
state = PLAY_STATE;
}
}
void drawGameOver() {
textAlign(CENTER, CENTER);
textSize(20);
text("you have crashed your car", width / 2, height / 2);
if (mousePressed) {
state = PLAY_STATE;
init();
}
}
void drawrestart() {
textAlign(CENTER, CENTER);
textSize(15);
text("press mouse to restart", 200, 400);
if (keyPressed) {
state = RESTART;
}
}
void drawPlay() {
background(0);
if (get(carx, cary) == vit) {
speedy = -1 * speedy;
}
fill(rod);
rect(carx, cary, 50, 30);
if (get(mouseX, 600) == color(255, 0, 0)) {
state = GAMEOVER_STATE;
}
fill(#FFFFFF);
rect(mouseX, 600, 30, 50);
carx += speedx;
cary += speedy;
speedy += accy;
}
The code you have at the moment only has one rectangle fall down from the top for each 'round' of the game. I'm not sure if you wanted to have multiple blocks falling; I think that would be a good next step.
For now, here's a simple hack which will cause the block to fall from a random position each time, like you requested.
At the very start of your code, outside of the functions, place:
boolean randomise;
Then, within void init() you should add:
randomise = true;
Finally, add this section into drawPlay(), right at the start of the function:
if (randomise){
carx = int(random(width-50));
randomise = false;
}
Note that a new random x co-ordinate will only generate every time you set the boolean 'randomise' to true again. So if you generate a new iteration with more than one block falling inside the drawPlay() function, you should bear this in mind and adjust the code accordingly.
------- [EDIT] -------
Hi, glad that this helped.
I've actually noticed another little issue which I will help you fix.
Currently, you are checking at mouseX to see whether there has been a collision. This works (mostly), but if the right side of the player's white car drives through the left edge of a red falling block, then the game continues as though nothing has happened. What should occur is that the game is over because a collision is detected. You want to find out if any part of the two shapes have overlapped.
To do this, you should alter the code like so. In drawPlay(), replace:
if (get(mouseX, 600) == color(255, 0, 0)) {
state = GAMEOVER_STATE;
}
with:
if (get(mouseX, 600) == color(255, 0, 0) || get(mouseX + 30, 600) == color(255, 0, 0)) {
state = GAMEOVER_STATE;
}
This is an OR statement - checking whether either side of the player's car has collided. This way, every time they bump into each other, the game will end.
Now for your question: how to add multiple cars?
There are a few ways you could go about this, but I'll show you the most straightforward.
In drawPlay(), you want to add this little if statement:
if (cary > height){
init();
}
Basically what we're doing here is checking if the previous red block/car has fallen off the bottom of the sketch. If it has, i.e. if the red block's y co-ordinate is larger than the height of the whole sketch, we call init() again. This will reset everything, including making randomise true. Once randomise is true, the previous code you added will select a random start point for the block, and it will fall all over again.
I hope you've understood everything I explained - whilst my code will fix your problem, the best way to learn is to try to solve things by yourself. Check out Dan Shiffman's videos on YouTube. These are a great starting place to get to grips with Processing - hopefully you'll be more confident writing your own code after following along with his examples :)
Use random to generate a random x coordinate:
carx = (int)random(0, width-50);
Reset the position and the speed of the care, once the car reached to bottom of the window:
void drawPlay() {
if (cary > height) {
carx = (int)random(0, width-50);
cary = 0;
speedy = 0;
}
// [...]

LibGDX - Map Boundaries

Synopsis
Well, I'm making a little top-down JRPG and today I was like 'Yeah, I'm gonna bust out this whole map collision thing!'. I failed.
Problem
So I went on the internet and looked up 'LibGDX Tiled Map Collision Detection' and found a really neat post about Map Objects so I added in a map object layer and did all that biz and came out with this little method to ensure the player can move freely around the map but at the same time can't exit it but each time I've tried it ends up with a horrible result such as the player moving off the screen. The latest error is that the player gets stuck doing a walk animation and can't move anywhere else!
Code
package com.darkbyte.games.tfa.game.entity.entities;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.math.Rectangle;
import com.darkbyte.games.tfa.game.entity.Entity;
import com.darkbyte.games.tfa.game.entity.SpriteSheet;
import com.darkbyte.games.tfa.game.world.map.MapManager;
import com.darkbyte.games.tfa.render.Batch;
import com.darkbyte.games.tfa.render.Camera;
public class Player extends Entity {
// The constructor for the player class
public Player(String name, SpriteSheet spriteSheet) {
super(name, spriteSheet);
direction = Direction.DOWN;
collisionBox = new Rectangle(x, y, 64, 64);
}
// A flag to see if the player is moving
private boolean isMoving;
// The variable that holds the state time
private float stateTime;
// The player's walking animations
private Animation[] walkAnimations = {
spriteSheet.getAnimation(8, 8, 1 / 16f),
spriteSheet.getAnimation(9, 8, 1 / 16f),
spriteSheet.getAnimation(10, 8, 1 / 16f),
spriteSheet.getAnimation(11, 8, 1 / 16f) };
// The player's static frames
private TextureRegion[] staticFrames = {
spriteSheet.getTexture(8, 0),
spriteSheet.getTexture(9, 0),
spriteSheet.getTexture(10, 0),
spriteSheet.getTexture(11, 0) };
// The render code for the player
#Override
public void render() {
// Makes the camera follow the player
Camera.setCameraPosition(x, y);
Batch.getGameBatch().setProjectionMatrix(Camera.getCamera().combined);
// Updates the state time
stateTime += Gdx.graphics.getDeltaTime();
// Gets the player's direction, if the player's moving, it sets the
// current frame to the frame that would be played at the current moment
// based on the state time
// If the player isn't moving, it sets the current frame to the static
// frame associated to the direction
switch (direction) {
case UP:
if(isMoving) {
currentFrame = walkAnimations[0].getKeyFrame(stateTime, true);
} else
currentFrame = staticFrames[0];
break;
case LEFT:
if(isMoving) {
currentFrame = walkAnimations[1].getKeyFrame(stateTime, true);
} else
currentFrame = staticFrames[1];
break;
case DOWN:
if(isMoving) {
currentFrame = walkAnimations[2].getKeyFrame(stateTime, true);
} else
currentFrame = staticFrames[2];
break;
case RIGHT:
if(isMoving) {
currentFrame = walkAnimations[3].getKeyFrame(stateTime, true);
} else
currentFrame = staticFrames[3];
break;
}
}
// The tick code for the player
#Override
public void tick() {
// The object to represent the bounds of the land on the map
RectangleMapObject land = (RectangleMapObject) MapManager.getCurrentMap().getMap().getLayers().get("collision").getObjects().get("land");
// Checks if the player is within the bounds of the map
if(land.getRectangle().contains(collisionBox)) {
// If the player is moving but the arrow keys aren't pressed, sets isMoving to false
isMoving = (isMoving && (Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP)
|| Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT)
|| Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN)
|| Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT)));
// Checks to see if the arrow / WASD keys are pressed and moves the
// player in the correct direction at the speed of 1.5 pixels/tick
// (45/second)
// It also sets the players state to moving and corresponds it's
// direction to the key pressed
// Doesn't move if opposing keys are pressed
if(Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP)) {
if(!(Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN))) {
direction = Direction.UP;
y += 1.5f;
isMoving = true;
}
}
if(Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT)) {
if(!(Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT))) {
direction = Direction.LEFT;
isMoving = true;
x -= 1.5f;
}
}
if(Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN)) {
if(!(Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP))) {
direction = Direction.DOWN;
y -= 1.5f;
isMoving = true;
}
}
if(Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT)) {
if(!(Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT))) {
direction = Direction.RIGHT;
x += 1.5f;
isMoving = true;
}
}
} else {
if(!isMoving) {
// If the player's just spawned puts the player to the map's spawn point
x = MapManager.getCurrentMap().getPlayerSpawnX();
y = MapManager.getCurrentMap().getPlayerSpawnY();
} else { // If not, it just moves them back till they're no longer out of the map
if(x > (land.getRectangle().getX() + land.getRectangle().getWidth())) x -= 1.5;
if(y > (land.getRectangle().getY() + land.getRectangle().getHeight())) y -= 1.5;
}
}
// Synchronises the collision box with the player's x and y position
collisionBox.x = x;
collisionBox.y = y;
}
// Returns if the player is moving
public boolean isMoving() {
return isMoving;
}
}
Can you guys make it so that when he reaches the border that he stops but he can still keep moving in other directions instead of staying static!
Thanks for reading!
At the moment it sounds you just copy/pasted it and you need to familiarize yourself with it first. If you don't know what it does then you should learn or stop the project imho.
Anyway, from what I can tell it's just a player class that handles the animation frames based on which direction it is moving. Nothing to do with collision detection at all. It does update some kind of collisionBox but functionality for this is handled elsewhere, perhaps in the parent class Entity?
My guess is that this is a tile map and units are restricted to the grid. It's pretty easy to detect if A tile exists or not.
private boolean tileExists(int tileX, int tileY, tile[][] map)
{
return tileX >= 0 && tileY >= 0 &&
tileX < map.length && tileY < map[0].length;
}
Now whenever a entity requests a move you should check if the destination is within the map bounds.
private void moveRequest(int destinationX, int destinationY, Tile[][] map)
{
//Just return if the tile is outside of the map
if (!tileExists(destinationX, destinationY, map) return;
//Same goes for your other checks...
//Return if the tile is not walkable
if (!tileIsWalkable(destinationX, destinationY, map) return;
//Return if the tile is already occupied
if (tileIsOccupied(destinationX, destinationY, otherEntities) return;
//etc..
//Now the move is valid and you can set it's state to moving in that direction.
}
Tile maps are not very hard to understand. I will make an attempt to give you some better insight into tile maps. You have a 2D array where you store your tiles in. Tiles have a width and a height and from that you can make your own tile engine:
//Find out which tiles to draw based on the camera position and viewport size.
int startX = (int)(camera.position.x - camera.viewportWidth / 2) / tileWidth;
int startY = (int)(camera.position.y - camera.viewportHeight / 2) / tileHeight;
int endX = (int)(startX + camera.viewportWidth / tileWidth) + 1;
int endY = (int)(startY + camera.viewportHeight / tileHeight) + 1;
//Loop using this data as boundaries
for (int y = startY; y < endY; y++)
{
for (int x = startX; x < endX; x++)
{
//If out of bounds continue to next tile.
if (!tileExists(x, y, map) continue;
//Now all we need to draw the on screen tiles properly:
//x == tile position x in array
//y == tile position y in array
//World position of this tile:
//worldX = x * tileWidth;
//worldY = y * tileHeight;
//Let's draw:
batch.draw(map[x][y].getTexture, worldX, worldY,
tileWidth, tileHeight)
}
}
There really is no magic involved here at all. Drawing only what is on screen like in the above example is very important for larger maps. Other then that you should draw thing in the back first. You have several options to do this, the easiest but least versatile is just a separate the ground from the objects that can obscure things and draw this later.
Characters, creatures or other entities can just use a world position and be easily converted back to tile position.
tileX = worldX / tileWidth;
tileY = worldY / tileHeight;
So if you want to move something with the world position calculate it's tile position first using the aforementioned method. Then lookup if this tile is valid to move to. Then block that tile for other and move to it.

Drawing mountains using 1px swing rectangles

I'm trying to draw mountains background using 1-width rectangles (something like integrals). I randomize the first point to the very left of the screen, randomize binary number and draw the first rectangle.
If binary number is 0, the next rectangle will be 1px lower. Else higher. And so on in the for loop.
There's a 95% chance that in the next loop the direction won't change and it will keep going higher/lower. And 5% chance the direction will change. For this I'm using randomized number from 1 to 1000.
public Landscape(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
Random rand = new Random();
int first = rand.nextInt((800 - 200) + 1) + 200;
g2d.fillRect(0, 800 - first, 1, first);
int d = first % 2;
for(int i = 1; i <= 800; i++) {
int choose = rand.nextInt((1000 - 1) + 1) + 1;
if(choose > 950) {
d = -(d);
}
if(d == -1) {
first += 1;
} else {
first -= 1;
}
g2d.fillRect(i, 800 - first, 1, first);
}
}
That's the effect I get in like half cases. Sometimes however I get something like this:
How is this possible? What's wrong here?
Here:
int d = first % 2;
d is either 1 or 0. If d is assigned 0, then if(d == -1) { is always false, and thus your graph will go monotonically downwards.
You are looking for a two state solution to decide whether the mountain goes up or down, so use a boolean. Perhaps something like:
boolean direction = rand.nextBoolean();
// 1 in 20 chance, same as 5 in 100, same as 50 in 1000 chance
if (rand.nextInt(20) == 0) {
direction = !direction;
}
if (direction) {
// ...
} else {
// ...
}
Myself, I'd look into using fractals.

How to do collision detection with many walls (maze)?

In my game, the player navigates a maze. I can't figure out how to do proper collision detection with the walls. It is easy to do collision detection for staying in a certain area:
if (x > rightWallX - playerWidth) x = rightWallX - playerWidth;
if (x < leftWallX) x = leftWallX;
//...
But how would I do collision detection for many walls?
I can do plain collision detection without correction (like if (intersecting) return true;), but I can't correct this correctly. If I just store the old x and y and reset them, then
The object never actually touches the wall
If the object can go up but is blocked to the right, it won't go up, it will just not move.
How is collision detection in a maze done?
The easiest way, once you have solved collision detection, to fix the collision is to move the actor to the closest valid position to where the actor would be were it not for the object it collides with. This assumes no inertia, but it is sufficient for maze-like games or top-down map-crawling games.
If you want to simplify your calculations further, you can limit yourself to detecting if changing the actor's x or y coordinate would be better. If your actor has an axis-aligned rectangular hit-box and all obstacles are axis-aligned rectangular as well (the simplest case), this assumption is indeed correct. However, the results might not be satisfactory in some other cases (potential artifact: speed boost from gliding diagonal walls - not the case in most maze games).
Keep in mind multiple collisions could happen concurrently (pushing against two walls). If there are no sharp angles between two walls that an actor could both intersect (say, if all your obstacles are axis aligned and sufficiently spaced), fixing each collision in turn will suffice - just don't stop after the first collision.
You can use Rectangle.intersects() method:
public Rectangle Player(){
return new Rectangle(PlayerX,PlayerY,PlayerWidth,PlayerHeight);
//we do this for getting players x and y values every tick
}
if(Player().intersects(new Rectangle(0,0,100,50)))//if(player touching wall)
new Rectangle(0,0,100,50) is just an example you can change it.
Ok so i'm currently making a 2D top down view game and I'm not sure how you created your maze. However, in my game my Level is created from a Tile[][] tiles = new Tile[levelWidth][levelHeight]; array. The way i handled collision detection was by checking the surrounding tiles to see if they were solid.
This is my getTile method.
public Tile[][] getTile(int x, int y) {
if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
return new VoidTile();
} else {
return tiles[x][y];
}
}
In my Tile.java class i have a isSolid() method which returns whether the tile is solid or not. All of my tiles extend my Tile.java so they inherit this method and I override it in their constructor. As i said previously, I am not sure whether or not you use the same style of level implementation as i do. However, It is good practice to do it this way :)
Personally, I am not a big fan of using the .intersects() and .contains() methods for Sprite collision detection. I mainly use them for buttons and alike.
Ok so,
In my player.java class i have a checkBlockedDirection(int x, int y) method and it looks like this.
public void checkBlockedDirection(int x, int y) {
boolean u = map.getTile(x, y - 1).isSolid();
boolean d = map.getTile(x, y + 1).isSolid();
boolean l = map.getTile(x - 1, y).isSolid();
boolean r = map.getTile(x + 1, y).isSolid();
if (u) {
uBlocked = true;
System.out.println("up tile blocked");
} else {
uBlocked = false;
}
if (d) {
dBlocked = true;
System.out.println("down tile blocked");
} else {
dBlocked = false;
}
if (l) {
lBlocked = true;
System.out.println("left tile blocked");
} else {
lBlocked = false;
}
if (r) {
rBlocked = true;
System.out.println("right tile blocked");
} else {
rBlocked = false;
}
}
Then in my player update method i have this
public void tick() {
float dx = 0;
float dy = 0;
if (input.up.isPressed()) {
direction = 0;
} else if (input.down.isPressed()) {
direction = 2;
} else if (input.left.isPressed()) {
direction = 3;
} else if (input.right.isPressed()) {
direction = 1;
} else {
direction = 4; // standing
}
checkBlockedDirection((int)x, (int)y);
if (input.up.isPressed() && y > 0 && !uBlocked) {
dy += -speed;
} else if (input.down.isPressed() && y < map.getHeight() - 1 && !dBlocked) {
dy += speed;
} else if (input.left.isPressed() && x > 0 && !lBlocked) {
dx += -speed;
} else if (input.right.isPressed() && x < map.getWidth() - 1 && !rBlocked) {
dx += speed;
}
x += dx;
y += dy;
}
Basically it just checks whether or not the blocks up, down, left, or right are solid. If they are solid then it wont move and if they arent solid then you can move in the desired direction.
Not sure if this helps or not but it's just my take on this kind of grid collision detection :)
Hope this helps :)
Enjoy

fixed timer and random direction

Hello as a starting Java programmer I am busy creating a simple Pacman game in Java just to exercise and I have created a method for the ghost to move randomly horizontal of vertical but I have a few problems with it I don't know how to force it to go left-right or up-down (so not at the same time) my code for the ghost right now is as follows:
public void moveUp() {
}
public void moveLeft() {
if (g1x >= 500) { g1x = 500; g1r = false; }
else if (g1x <= 0) { g1x = 0; g1r = true; }
}
public void moveRight() {
if (g1x >= 500) { g1x = 500; g1r = false; }
else if (g1x <= 0) { g1x = 0; g1r = true; }
}
public void moveDown() {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// pacman movement
diameter = 25;
pacman.drawPacMan(g, getHorPlaats(), getVerPlaats(), diameter, getView(), Color.yellow);
// ghosts movement
g1x += ghostSpeed * (Math.random() > 0.5? 1 : -1); // random direction
Random randomGen = new Random();
// generate a random number, between 0 - 3
int randomize = randomGen.nextInt(4);
switch(randomize) {
case 0:
moveUp();
System.out.println("up");
break;
case 1:
moveLeft();
System.out.println("Left");
break;
case 2:
moveRight();
System.out.println("Right");
break;
case 3:
moveDown();
System.out.println("down");
break;
}
ghost.drawGhost(g, randomize, 40, diameter, Color.red);
}
I have used the randomize variable for the direction as you can see and the horizontal position is hardcoded but the horizontal position is also stated by randomize but if I use it for both it makes some weird diagonal movements
the next problem is that i use a timer in my construction like this
public PacMan() {
// create timer and start timer
javax.swing.Timer autoKlik = new javax.swing.Timer(WACHTTIJD, this);
autoKlik.start();
}
so the random values for the directions is changing to fast ( 500ms ) but the speed also configures the gameplay speed so I think I made a logical mistake but Im not sure how to solve this.. do I have to seperate the actions maybe? or is there a easier way to achieve this please share your skills with me I am motivated to learn :) and if you might need more code I could post it here or give a link to my github account so you can check it out :)
Thanks in advance!
link to the full source: pacman game source
I suggest to separate the concerns:
a set of classes to model the simulation contains only the entities and the logic
a set of graphic classes which draw the pacman
a controller to handle actions and delegate them to the model, fired by the swing classes
In paint() method, for performance reason, do only the painting, NEVER 'new' nor call complex methods. Paint are called very often by the framework.

Categories

Resources