I am using Slick and Tiled2D to make a top-down RPG style game. I am trying to do collision, but the player seems to be able to go through blocks that are on the left side of a building, or the left half of a block. The full project is here: http://github.com/Cj1m/RPG
Here is my code for the player movement and collision detection:
#Override
public void update(GameContainer gc, int delta) throws SlickException {
input = gc.getInput();
if(input.isKeyDown(Input.KEY_W)){
if(!isBlocked(x, y - delta * 0.1f)){
y-=0.1 * delta;
timer(0,1,delta);
}
}else if(input.isKeyDown(Input.KEY_S) && y < screenBottomEdge){
if (!isBlocked(x, y + playerHeight + delta * 0.1f)){
y+=0.1 * delta;
timer(0,0,delta);
}
}else if(input.isKeyDown(Input.KEY_A) && x > screenLeftEdge){
if (!isBlocked(x - delta * 0.1f, y)){
x-=0.1 * delta;
timer(0,2,delta);
}
}else if(input.isKeyDown(Input.KEY_D) && x < screenRightEdge){
if (!isBlocked(x + playerWidth + delta * 0.1f, y)){
x+=0.1 * delta;
timer(0,3,delta);
}
}
}
and
private boolean isBlocked(float x, float y) {
int xBlock = (int)x / 30;
int yBlock = (int)y / 30;
return blocked[xBlock][yBlock];
}
I guess the x and y in isBlocked are the player's pixel-accurate x and y-positions, while xBlock and yBlock are the tile-accurate positions.
When you say they go through half of the block this seems to me like a rounding-problem at
int xBlock = (int)x / 30;
int yBlock = (int)y / 30;
Try something along the lines of
(int) Math.round(x/30.0);
Related
I have a problem in regards to parallelism in javafx. More specifically, dividing the canvas of my program to run with multiple threads. When compiled, the program glitches out and doesn't work as supposed to. The code in the thread class is supposed to print out the Mandelbrot set, and the code in the application class is dividing the canvas into different parts that each should run in parallel. Here is the code:
public void MandelbrotSet(int n) {
int widthh = (int)canvas.getWidth();
int portion = widthh / n;
for (int i = 0; i < n; i++) {
int startX = i * portion;
int endX = startX + portion;
myMandelbrotParallelTEST2 thread = new myMandelbrotParallelTEST2(startX, endX, image, width, height, maximumIterations, canvas, zoom, xPos, yPos, hue, brightness, saturation, R, G, B);
thread.start();
//would add thread.join() here with try and catch
}
canvas.getGraphicsContext2D().drawImage(image, 0, 0);
}
this is how the code in the Thread class looks:
#Override
public void run(){
double centerY = canvas.getWidth() / 2.0;
double centerX = canvas.getHeight() / 2.0;
for (int x = start; x < end; x++) {
for (int y = 0; y < canvas.getHeight(); y++) {
double cr = xPos / width + (x - centerY) / zoom;
double ci = yPos / height + (y - centerX) / zoom; //getting position of the points on the canvas
int iterationsOfZ = 0;
double zr = 0.0;
double zi = 0.0;
while (iterationsOfZ < maximumIterations && (zr * zr) + (zi * zi) < 4) {
double oldZr = zr;
zr = (zr * zr) - (zi * zi) + cr;
zi = 2 * (oldZr * zi) + ci;
iterationsOfZ++;
}
int iterations = iterationsOfZ;
if (iterations == maximumIterations) { //inside the set
imagee.getPixelWriter().setColor(x, y, Color.rgb(R, G, B));
} else if (brightness == 0.9) { //white background
imagee.getPixelWriter().setColor(x, y, Color.hsb(hue, iterations / maximumIterations, brightness));
} else if (hue == 300) { //colorful background
imagee.getPixelWriter().setColor(x, y, Color.hsb(hue * iterations / maximumIterations, saturation, brightness));
} else if (hue == 0 && saturation == 0 && brightness == 1) {
imagee.getPixelWriter().setColor(x, y, Color.hsb(hue, saturation, brightness));
} else { //black background
imagee.getPixelWriter().setColor(x, y, Color.hsb(hue, saturation, iterations / brightness));
}
}
}
//canvas.getGraphicsContext2D().drawImage(imagee, 0, 0);
}
[this is how the program looks, and while panning around it glitches even more, but the execution time is really fast, which means that it is ran concurrently.]enter code here(https://i.stack.imgur.com/IZUfY.png)
I found that adding thread.join() fixes the problem, but then the program is ran on a single thread. Could anyone help me out resolve this issue?
What you are trying to do cannot be done with a Canvas because of the fx application thread restiction which has already been mentioned.
But it can be done via the WritableImage of JavaFX 13+ with support for Buffers. Writing into the buffer is not restricted in the above way and can thus be done in parallel with high performance.
I have compiled some examples (not any parallel ones) of how to use WritableImages with Buffers here: https://github.com/mipastgt/JFXToolsAndDemos
I am trying to make a game where enemies spawn from the top (like a vertical scrolling game) and one kind of enemy will basically follow the player's X coordinate while going down. The enemy class is called Follower and right now it does points to the player (see update function on Follower) but it's not as accurate as I need it to be. For example, if the player accelerates, the follower won't be able to see him all the time.
One way to look at it is that I want the position of the player to be a coordinate in a radiant system and make the vertices of my Follower accurately just rotate and create a straight line looking at it every frame
here is the Follower Class:
public class Follower {
Player target; //follow this
//position
private Vector2 position;
private float x;
private float y;
//speed
private Vector2 velocity;
private float speed;
private float radians;
private float faceTarget;
//dimensions
private float[] shapeX;
private float[] shapeY;
private int numPoints; //vertices for the shape
private boolean remove; //to remove from the game
public Follower(float x,float y, Player target){
this.target = target;
this.x = x;
this.y = y;
velocity = new Vector2(0, 0);
numPoints = 4;
speed = 200;
shapeX = new float[numPoints];
shapeY = new float[numPoints];
radians = 3.1415f / 2;
setShape();
}
public void setShape(){
//top vertice
shapeX[0] = x + MathUtils.cos(radians) * 30;
shapeY[0] = y + MathUtils.sin(radians) * 30;
//left vertice
shapeX[1] = x + MathUtils.cos(radians - 4 * 3.1415f / 10) * 30;
shapeY[1] = y + MathUtils.sin(radians - 4 * 3.1415f / 10) * 30;
//bottom vertice
shapeX[2] = x + MathUtils.cos(radians + 3.1415f) * 60;
shapeY[2] = y + MathUtils.sin(radians + 3.1415f) * 60;
//left vertice
shapeX[3] = x + MathUtils.cos(radians + 4 * 3.1415f / 10) * 30;
shapeY[3] = y + MathUtils.sin(radians + 4 * 3.1415f / 10) * 30;
}
public boolean shouldRemove() {
return remove;
}
public void update(float dt) {
float angle = (float) Math.atan2(target.getPosition().y - y, target.getPosition().x - x); //angle between the follower and target
velocity.set((float) Math.cos(angle) * speed , -speed); //setting direction to follow the target
radians += Math.cos(angle) * dt; //THIS HERE IS MAKING IT ROTATE
x += velocity.x * dt;
y += velocity.y * dt;
setShape();
if(y <= 0 - 60)
remove = true;
else
remove = false;
}
public void draw(ShapeRenderer sp){
sp.setColor(1, 1, 1 ,1);
sp.begin(ShapeRenderer.ShapeType.Line);
for(int i = 0, j = shapeX.length - 1;
i < shapeX.length;
j = i++) {
sp.line(shapeX[i], shapeY[i], shapeX[j], shapeY[j]);
}
sp.end();
}
}
I am not adding the GameScreen because I do not see the need of showing how they are rendered, either way, it'll stay the same.
Also, with the line of code, I am using the Follower points to the player with the bottom vertice as the "eyes"
Thanks for the answers!
I'm doing this bouncing ball problem and I have was given this formula: (velocity) vx = v0*cos(angle). and (x-position) x = v0*cos(angle)*t. However, I cannot get the ball to bounce properly.
The problem is that after the ball hits the right vertical wall, it starts to bounce inside certain range on the right-hand-side of the window. (y and vy shouldn't matter in this case.)
How can I fix this weird bouncing problem to make it bounce property in the x direction?
public class GamePanel2 extends JPanel implements KeyListener, ActionListener{
Timer tm = new Timer(60, this); //this refers to the ActionListener
public int score = 0;
public GamePanel2(){
addKeyListener(this);
setFocusable(true);
setBackground(Color.BLACK);
}
public int getScore() {
return score;
}
public double v0 = 100;
public double t = 0;
public double angle = Math.PI/2.5;
public double x = 0;
public double y = 0;
public double vx =0;
public double vy = 0;
public int move = 0;
public int paddlex =0;
public void paintComponent(Graphics g){
int h = getHeight();
int w = getWidth();
vx = v0*Math.cos(angle);
vy = v0*Math.sin(angle);
Graphics2D g2d = (Graphics2D)g;
g2d.translate(0.0,h);
g2d.scale(1.0, -1.0);
//ball
g2d.setColor(Color.GREEN);
g2d.fillOval((int)Math.round(x), (int)Math.round(y+6), 20, 20);
//paddle
g2d.setColor(Color.RED);
g2d.fillRect(paddlex + move, 0, 60, 6);
repaint();
}
//KeyListener methods
#Override
public void keyPressed(KeyEvent arg0) {
if(arg0.getKeyCode() == KeyEvent.VK_SPACE){
tm.start();
}
else if(arg0.getKeyCode()==KeyEvent.VK_ESCAPE){
tm.stop();
}
if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
move += 30;
}
//if pressed right key
if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
move -= 30;
}
repaint();
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
#Override
public void actionPerformed(ActionEvent arg0) {
t = 0.2;
vy -= 9.8;
x += vx;
y += (vy)*t-(t*t*9.8)*0.5;
if( x<= 0){
vx = v0*Math.cos(angle);
}
if (x>=getWidth()-20){
vx =-(v0*Math.cos(angle));
}
repaint();
}
}
You're not even close. The differential equations of motion for a ball with gravity supplying the only force are
d^2x/dt^2 = -9.8 and d^2x/dt^2 = 0
You need to integrate these equations. For this purpose, you need to get rid of the second degree differentials by introducing a new variable:
dv_y/dt = -9.8 and dv_x/dt = 0
dy/dt = v_y dx/dt = v_x
With Euler forward differences (the simplest possible integration method), this becomes:
v_y[i+i] = v_y[i] + h * -9.8
y[i+1] = y[i] + h * v_y[i]
v_x[i+1] = v_x[i] + h * 0 // x-velocity is constant!
x[i+1] = x[i] + h * v_x[i]
When the ball encounters a vertical wall with a perfectly elastic collision, the x velocity instantly changes sign. When it hits the floor or ceiling, the y velocity changes sign.
Your formula provides only the initial values of v_x and v_y. All x and y values after are results of the above Euler equations. In pseudocode it will look something like this:
// Initialize the velocity components.
vx = v0 * cos(theta)
vy = v0 * sin(theta)
// Initialize the position of the ball.
x = R // in the corner of the first quadrant
y = R
// Choose a time increment.
h = < a very small number of seconds >
// Start the clock.
t = 0
while (t < END_OF_SIMULATION) {
draw_ball(x,y)
x = x + h * vx;
y = y + h * vy;
vy = vy - h * 9.8;
// Check for bounces
// Assumes box has corners (0,0), (W,H)
if ((vx < 0 and x < r) or (vx > 0 && x > W-r)) x = -x;
if ((vy < 0 and y < r) or (vy > 0 && y > H-r)) y = -y;
t = t + h
}
Note that that 9.8 means that the units are meters and seconds. You need to scale pixels in the Java window and use a timer to get a realistic result.
To roughly simulate lossy collision, you can steal some velocity on every bounce:
x = -<a number a bit less than 1.0> * x and
y = -<a number a bit less than 1.0> * y
With these, the ball will slow down a bit every time it hits a wall.
I can't find where you're changing the angle after detecting a bounce. I also don't see bounds checking for all four sides of the windows the ball is in.
There's a related bug you might run into where there's a double bounce in a corner that leaves the ball outside the window after all the calculations are done. Think about ways to handle that case.
I'm working on a small FPS (personal project), written in java and using JBullet (port of bullet). I got a basic rendering engine with OpenGL and bullet works well. I've implemented a character using a RigidBody, but my character keeps going through every object, except the ground. here is a demo of what happens
This is my first project involving bullet, but I didn't find anyone having this strange behavior on google (nor StackExchange).
Here is a summary of my code.
Main class:
public class Fps {
public static void main(String[] args) {
//Initialization stuff
// Loading level
// Creating DiscreteDynamiWorld
player = new Player(0, -50, 0);
//Mainloop:
while(!Display.isCloseRequested()) {
//GL stuff
//InputHandleR.poll(player);
update();
render();
//GL and timing stuff
}
}
public static void update() {
world.stepSimulation((float) delta / 1000f, 10);
for(int i = 0; i < objects.size(); i++)
objects.get(i).update();
}
public static void render() {
// stuff
}
}
Player:
public class Player implements tk.azertyfun.fps.objects.Object {
// Attributes...
public Player(float x, float y, float z) {
c = new Camera(x, y, z); // Objects that has pos, yaw, pitch, and calls glRotate and glTranslate each frame
//Creating RigidBody with a CapsuleShape (using BoxShape doesn't change anything)
shape = new CapsuleShape(1.75f * CHAR_SCALE, 1.75f * CHAR_SCALE);
Transform trans = new Transform(new Matrix4f(new Quat4f(1, 0, 0, 0), new javax.vecmath.Vector3f(x, y, z), 1f));
motionState = new DefaultMotionState(trans);
javax.vecmath.Vector3f inertia = new javax.vecmath.Vector3f(0, 0, 0);
shape.calculateLocalInertia(1, inertia);
RigidBodyConstructionInfo bodyRbCi = new RigidBodyConstructionInfo(1, motionState, shape, inertia);
bodyRb = new RigidBody(bodyRbCi);
//We wan't our body to stay up
bodyRb.setSleepingThresholds(0.0f, 0.0f);
bodyRb.setAngularFactor(0.0f);
Fps.btWorld.addRigidBody(bodyRb); //Adding body to the world (already trying adding it in the main class, doesn't change anything).
bodyRb.setGravity(new javax.vecmath.Vector3f(0, 50, 0)); //Strange behavior that seems linked to my bug ; this body doesn't act like others, and has reversed gravity.
}
// This function is called by InputHandler and just uses body.setLinearVelocity(vel);. X and Z velocity is reset each frame (i want my player reactive, not walking with soap instead of foots). Anyway, it doesn't change our bug if not reset.
public void move(boolean left, boolean right, boolean forward, boolean backwards, boolean up, boolean down) {
float velX = 0;
float velY = 0;
float velZ = 0;
javax.vecmath.Vector3f vel = new javax.vecmath.Vector3f();
bodyRb.getLinearVelocity(vel);
velY = vel.y;
double delta = Util.getDelta();
if(forward) {
velX -= SPEED * (float) (Math.sin(Math.toRadians(c.yaw))) * delta;
velZ += SPEED * (float) (Math.cos(Math.toRadians(c.yaw))) * delta;
}
if(backwards) {
velX += SPEED * (float) (Math.sin(Math.toRadians(c.yaw))) * delta;
velZ -= SPEED * (float) (Math.cos(Math.toRadians(c.yaw))) * delta;
}
if(left) {
velX -= SPEED * (float) (Math.sin(Math.toRadians(c.yaw - 90))) * delta;
velZ += SPEED * (float) (Math.cos(Math.toRadians(c.yaw - 90))) * delta;
}
if(right) {
velX += SPEED * (float) (Math.sin(Math.toRadians(c.yaw - 90))) * delta;
velZ -= SPEED * (float) (Math.cos(Math.toRadians(c.yaw - 90))) * delta;
}
if(up)
velY += SPEED * (float) delta / 7f;
if(down)
velY -= SPEED * (float) delta / 7f;
javax.vecmath.Vector3f velocity = new javax.vecmath.Vector3f(velX, velY, velZ);
bodyRb.setLinearVelocity(velocity);
}
//Called each frame, sets the camera pos to the body pos.
#Override
public void update() {
Transform trans = new Transform();
bodyRb.getMotionState().getWorldTransform(trans);
c.pos.set(trans.origin.x, trans.origin.y, trans.origin.z);
}
}
Why isn't my body concerned by physics like the other ones? I have to revert the gravity for it and the only colliding object is the ground (which may be as buggy as the player). It looks like I didn't understand something.
The problem:
I've got this "Shot" class. In the code, the target variables are the mouseX and mouseY.
So when i click the mouse button, my player class will create a new shot object.
But the shooting is inaccurate.
How can i calculate the correct dx and dy?
If i add the dx and dy to the "bullet's" x and y, the bullet will move to the mouse's direction.This is what i want. The mouse position is stored in targetX and targetY, when the object is created. This is the point what the oval wants to reach.
Links:
The game (finished)
The code (from Shot.java):
public class Shot extends Entity {
private float targetX, targetY;
public Shot(World world, float x, float y, int width, int height, Color color, float targetX, float targetY) {
super(world, x, y, width, height, color);
this.targetX = targetX;
this.targetY = targetY;
}
#Override
public void render(GameContainer gc, Graphics g, Camera camera) {
g.setColor(color);
g.fillOval(x - camera.getX(), y - camera.getY(), width, height);
}
#Override
public void update(GameContainer gc, int delta) {
float dx = targetX - x;
float dy = targetY - y;
x += dx * delta * .001f;
y += dy * delta * .001f;
}
}
I tried this, but still not work:
#Override
public void update(GameContainer gc, int delta) {
float length = (float) Math.sqrt((targetX - x) * (targetX - x) + (targetY - y) * (targetY - y));
double dx = (targetX - x) / length * delta;
double dy = (targetY - y) / length * delta;
x += dx;
y += dy;
}
I did it! Here is my solution:
The problem was that, the target was the window's mouse position, and not the world's mouse position.
This is how i calculated the world's mouse positions:
float mouseWorldX = x + (mouseX - screen_width / 2); // x = player's x position
float mouseWorldY = y + (mouseY - screen_height / 2); // y = player's y position
This is code from my game at the moment is used to move a unit to the mouse when the right mouse button is pressed:
length = Math.sqrt((target_X - player_X)*(target_X - player_X) + (target_Y - player_Y)*(target_Y - player_Y)); //calculates the distance between the two points
speed_X = (target_X - player_X) /length * player_Speed;
speed_Y = (target_Y - player_Y) /length * player_Speed;
This will move an object to the target in a line at a set speed.
Edit: this is the actual code right from my game
if(input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON))
{
length = (float) Math.sqrt((player_waypoint_X - player_X)*(player_waypoint_X - player_X) + (player_waypoint_Y - player_Y)*(player_waypoint_Y - player_Y));
velocityX = (float) (player_waypoint_X - player_X) /length * (float) PlayerStats.player.db_player_Speed;
velocityY = (float) (player_waypoint_Y - player_Y) /length * (float) PlayerStats.player.db_player_Speed;
player_waypoint_X = input.getMouseX() - 2;
player_waypoint_Y = input.getMouseY() - 2;
}
For testing purposes the velocity's are defined in the init method along with length. Every time the right mouse is pressed the waypoints's X and Y are changed to the mouse location.
I learned this from this question
velocity calculation algorithm.
in order to make the bullets not all change direction every shot, create an array list so that each bullet fired has its own x and y velocity