So I'm trying to implement a simple mouseLook method for exploring a game world in LWJGL. For now I just want it to work on the rotation-Y axis. The movement at first was limited because of the dimensions of the screen stopped the mouse from moving. So i hid the cursor and set the x-position of the mouse to 0 after deltaX is returned. When i wrote it out on paper the calculations seem to be right I think, however when i run it, the rotation keeps snapping back to 0, and creates a jitter effect. How can i solve this?
public void rotate() { //rotate the camera
System.out.println(getGlobalDX() + " " + MouseInfo.getPointerInfo().getLocation().getX());
float speed = 0.03f;
//START OF CODE TO IGNORE
float ratioX = (float)Display.getWidth() / 360;
float ratioY = (float)Display.getHeight() / 360;
float mouseRotX = Mouse.getX() / ratioX;
float mouseRotY = Mouse.getY() / ratioY;
//END OF CODE TO IGNORE
rotY += getGlobalDX() * speed; // add the deltaX of the mouse position X and multiply it by our speed in order to rotate the camera based on the mouse
lockCursor();
}
public float getGlobalDX() { //returns the difference between the current mouse position and the mouse position during the last frame
frames += 1; //add 1 to frames variable every frame
if(frames >= 1.5) { //if 1.5 frames have passed since last method call, run method again. this is to smooth things out since it doesnt work properly every frame
float mouseX = (float) MouseInfo.getPointerInfo().getLocation().getX(); //get x pos of mouse
frames = 0; //set frames to zero
if(lastMouseX != mouseX) { //if the lastmouse position isnt equal to our current mouse position, then continue
if(mouseX == 963) { //if the mouse position is equal to the centered X position of the screen then continue
lastMouseX = (float) MouseInfo.getPointerInfo().getLocation().getX(); //set this variable to the new x position
System.out.println("returning zero"); //debug by checking if this code runs (it does)
return 0; //return 0 since we dont want to undo the position we returned last frame
}
float deltaX = (float) (mouseX - lastMouseX); // difference between current mouse position and last to get the overall change in position
lastMouseX = (float) MouseInfo.getPointerInfo().getLocation().getX(); //set to new x position
MouseInfo.getPointerInfo().getLocation().setLocation(MouseInfo.getPointerInfo().getLocation().getX()/2, MouseInfo.getPointerInfo().getLocation().getY()/2); // set mouse position to 0 for infinite movement
return deltaX; //return the overall change in position and add it to the rotation Y of our camera
} else { // return 0 if the lastMouse position is equal to the current mouse position, since there was no change in position
return 0;
}
} else { //return 0 since a frame was skipped
return 0;
}
}
Rather than resetting the position of the mouse yourself just call Mouse.setGrabbed(true) before you start using the mouse for this.
Related
I have implemented basic collision detection in my top down 2d scrolling game. If the player moves a large distance, it will skip over the areas around it, because the collision detection checks around the player after the movement. As well as this, the player can get stuck in tiles.
I have tried recursively cutting the motion in half to check if it can find a smaller amount of motion that doesn't end in a collision, but I can't seem to get this to work for either problems. It also causes a StackOverflow error.
In the following code, x() represents the player's X location, from the bottom left. y() is the Y location. size is the player's width and height, and prevX and curX are temporary variables. The tiles method gets all tile locations in a certain radius from the player.
move(motionx, motiony);
if (x() - size()/2 < 0)x(size()/2);
if (y() - size()/2 < 0)y(size()/2);
if (x() + size()/2 > game.mapWidth * game.chunkWidth * size)x(game.mapWidth*game.chunkWidth*size - size()/2);
if (y() + size()/2 > game.mapHeight * game.chunkHeight * size)y(game.mapHeight*game.chunkHeight*size - size()/2);
float curX = x();
boolean updateX = true;
boolean updateY = true;
for (float[] tile : game.tiles((float)Math.ceil((double)size()/(double)size))) {
Tile t = game.tile(tile[0], tile[1]);
if (t == null) continue;
if (t.solid && game.collision(game.coordinate(), tile)) {
factor(1.0f - t.bounce, 1.0f - t.bounce);
x(game.prevX);
updateX = false;
if (t.solid && game.collision(game.coordinate(), tile)) {
x(curX);
updateX = true;
y(game.prevY);
updateY = false;
if (t.solid && game.collision(game.coordinate(), tile)) {
x(game.prevX);
updateX = false;
}
}
}
}
if (updateX)game.prevX = x();
if (updateY)game.prevY = y();
I hoped this would flawlessly prevent a player from moving onto a solid tile, but it obviously has problems. I am not great at collisions, but am willing to try anything. It sometimes skips over tiles and/or gets stuck.
I'm currently working on a Top-Down-Shooter and having some issues with collision.
My world is made of tiles (64x64). The tiles and the entities are rectangles. The player moves with a speed of e.g 2.74 (and not in pixels for smoother movement). But when it comes to the collision between the player (an entity) and a wall i have some issues. To check if there is a collision i take the current position of my player and his movement speed to calculate where his next position would be and if there is any collision. But i check every pixel on the way, so i cant skip an obstacle even if the movement speed is very high. Let's just say the players current position is X:200 Y:200 and he moves 2.74 Pixels a tick in the x direction. My game now checks if there is any collision at X:201 Y:200, X:202 Y:200 or X:202.74 Y:200 and if not moves the player to that position. If I now try to move the player further in the x direction and there is a wall 0.26 Pixels away the player wont move and leave a tiny gap. I tried to calculate the distance between player and wall and add this amount to the players position but for that I need to know which side of the wall the player hits. Also I want the player to be able to move up and down when the wall he hits is in front of him and the other way around.
Here is my collision method (in Java):
public static boolean collision(float ex, float ey, int width, int height) { // ex, ey would be the next position of the player
if (ex < 0 || ex + width > worldWidth || ey < 0 || ey + height > worldHeight) return true; // checks if this position is in the world
int firstTileX = (int) (ex / Tile.TILE_SIZE); // calculates tiles he could possible collide width
int firstTileY = (int) (ey / Tile.TILE_SIZE);
int lastTileX = (int) ((ex + width - 1) / Tile.TILE_SIZE);
int lastTileY = (int) ((ey + height - 1) / Tile.TILE_SIZE);
for (int y = firstTileY; y <= lastTileY; y++) {
if (y < 0) continue; // checks for out of bounds
if (y >= worldTileHeight) break;
for (int x = firstTileX; x <= lastTileX; x++) {
if (x < 0) continue;
if (x >= worldTileWidth) break;
if (tiles[y][x].solid) return true; // if the tile is solid -> collision found
}
}
return false; // no collision found
}
And my movement method:
public void move(float xa, float ya) {
float nx, ny;
while (xa != 0 || ya != 0) {
nx = x;
ny = y;
if (xa != 0) {
if (Math.abs(xa) > 1) { // if the x-speed is greater than 1
nx = x + MathUtil.abs(xa); // returns -1 for negative numbers and 1 for positiv
xa -= MathUtil.abs(xa);
} else { // less than 1
nx = x + xa;
xa = 0;
}
}
if (ya != 0) { // same here
if (Math.abs(ya) > 1) {
ny = y + MathUtil.abs(ya);
ya -= MathUtil.abs(ya);
} else {
ny = y + ya;
ya = 0;
}
}
if (!Level.collision(nx, ny, width, height)) setPosition(nx, ny); // checks if there is an collision and sets the new position if not
else if (!Level.collision(nx, y, width, height)) x = nx; // if there was a collision check if the player can walk in x direction
else if (!Level.collision(x, ny, width, height)) y = ny; // or in y direction
}
}
My problem is the pretty much the same as CoderMusgrove's problem in his post (Pixel-perfect collision and doubles):
Summary & Question
I have a problem where if the speed of an entity isgreater thanthe distance from the tile it is going into, it will leave at least a pixel in between itself and the tile, and I really don't like this. What kind of algorithm could I use that will find the tiniest difference between the entity and the tile?
If you need any additional information, I will be glad to add it.
Thanks for your help!
Easily resolvable by changing your interpretation.
You are retaining a fractional position for the purpose of fine grained speed. Ignore the fraction for the purpose of collision detection and display (if you were to do sub-pixel rendering, do the collision on the subpixel rendering accurarcy level).
int screenX = (int) Math.round(objX);
int screenY = (int) Math.round(objY);
// rendering and collision detection based on rounded position
after creating a very simple animation using libGDX i have some questions I'd like to clarify in order to make sure I understand everything prior to start with any other development with more complexity.
I have a box created like this:
public void createBaseCube(Model modelCube) {
ModelBuilder modelBuilder = new ModelBuilder();
modelCube = modelBuilder.createBox(1f, 1f, 1f,
new Material(ColorAttribute.createDiffuse(Color.GREEN)),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal);
this.cubeInstance.transform.translate(0.5f, 0.5f, 0.5f);
}
As it is centered in position (0,0,0) and a want its corner to be allocated in (0, 0, 0) I applied the translation in last line.
Here is how it looks like (I added a set of tiles to have some reference):
Afterwards, I create the animation. I want to overturn the box, so it will be positioned over the white tile, and rotating over its bottom-right edge
public class CubeAnimation {
...
<<definition of attributes>>
...
public CubeAnimation (ModelInstance cubeModel, float fromAngle, float toAngle, float speed, float alpha){
this.cubeInstance = cubeModel;
this.fromAngle = fromAngle; //value set to 0
this.toAngle = toAngle; //value set to 90f
this.speed = speed; //value set to 1f
this.alpha = alpha; //value set to 0
}
public void update(float delta) {
alpha += delta * speed;
if (alpha >= 1f) {
finished =true;
return;
}
float angle = alpha * (toAngle - fromAngle);
fromAngle = angle;
Vector3 t = new Vector3(0.5f, -0.5f, 0);
cubeInstance.transform.idt().translate(t).rotate(Vector3.Z, -angle).translate(t.scl(-1));
}
Everything seems to be fine, and code is quite simple, BUT (and here are the issues) when applying the animation, the box is translated to the center again (so first translate when box was created is undone), and -surprise- although I'm passing 90f as parameter to the animation, cube only rotates 45 degrees (when I set 180, it rotated as expected: 90).
Here how it looks like after the animation:
What is wrong here? Thanks in advance for your help!
You want to rotate the cube from angle fromAngle to angle toAngle
You are attempting to do so gradually by calculating the percentage completed over time, stored in your alpha variable.
alpha += delta * speed;
if (alpha >= 1f) {
finished =true;
return;
}
This part is fine for calculating the percentage as an angular-velocity multiplied by time passed. ie
angle_percentage/seconds * seconds_passed
You then get the distance between the start and stop angles in this line
float angle = alpha * (toAngle - fromAngle);
This code works for a starting angle of 0, but will fail for non zero starting points. The equation for a line is y = mx + b, so to correct this, you should include the b value:
float angle = fromAngle + alpha * (toAngle - fromAngle);
This will start the animation at fromAngle and push it over the distance required.
The extra line fromAngle = angle; changes your starting location on every iteration, so you end up with an unpredictable animation, which will be different depending on the speed you choose... I'm fairly certain the factor of two is merely a coincidence ;)
Finally this loop ends when the value is set to 100%, but never actually updates to 100%. Try this instead.
public void update(float delta) {
alpha += delta * speed;
if (alpha <= 1f) {
float angle = fromAngle + alpha * (toAngle - fromAngle);
Vector3 t = new Vector3(0.5f, -0.5f, 0);
cubeInstance.transform.idt().translate(t).rotate(Vector3.Z, -angle).translate(t.scl(-1));
} else {
finished = true;
}
}
For some reason when i make my map bigger then 15 x 25 the camera gets all buggy, at the top part of the map the camera jumps showing the bottom of the map, and at the bottom it jumps to the top.
Here's the code for it:
public int getXOffset(){
int offset_x = 0;
//the first thing we are going to need is the half-width of the screen, to calculate if the player is in the middle of our screen
int half_width = (int) (Game.WINDOW_WIDTH/Game.SCALE/2);
//next up is the maximum offset, this is the most right side of the map, minus half of the screen offcourse
int maxX = (int) (map.getWidth()*32)-half_width;
//now we have 3 cases here
if(player.getX() < half_width){
//the player is between the most left side of the map, which is zero and half a screen size which is 0+half_screen
offset_x = 0;
}else if(player.getX() > maxX){
//the player is between the maximum point of scrolling and the maximum width of the map
//the reason why we substract half the screen again is because we need to set our offset to the topleft position of our screen
offset_x = maxX-half_width;
}else{
//the player is in between the 2 spots, so we set the offset to the player, minus the half-width of the screen
offset_x = (int) (player.getX()-half_width);
}
return offset_x;
}
public int getYOffset(){
int offset_y = 0;
int half_heigth = (int) (Game.WINDOW_HEIGTH/Game.SCALE/2);
int maxY = (int) (map.getHeight()*32)-half_heigth;
if(player.getY() < half_heigth){
offset_y = 0;
}else if(player.getY() > maxY){
offset_y = maxY-half_heigth;
}else{
offset_y = (int) (player.getY()-half_heigth);
}
return offset_y;
}
In my render method i use this:
map.render(-(offset_x%32), -(offset_y%32), offset_x/32, offset_y/32, 33, 19);
Here's a .gif of the problem, I'm jumping up and down in this: http://i.gyazo.com/11efe44d6e872c334533cd3a40ddf2b9.gif
Instead of rendering an offset to your map, try just using
g.translate(camera.x-(width/2),camera.y-(height/2);
It's much more manageable this way, your camera's co-ordinates would be tied to the players.
I have a circle that moves from point A to a random point B. When the object nears point B, a new random target location gets chosen. If the circle is moving parallel to the X-axis or Y-axis the object goes through all the pixels in the way and leaves a solid trace. But if the circle moves diagonally, it skips pixels and shakes slightly, making the animation not smooth and leaves a trace with unpainted pixels.
My algorithm is:
calculate the X and Y distances
check if the circle is near
if so, choose the new destination
if 2. is true, find the real distance using Pythagoras' theorem
if 2. is true, calculate the X and Y speed (the change of the coordinates)
set the new coordinates (no matter if 2. is true or not)
And here is the code:
public void move ()//движение
{
//finds the X and Y distance to the destination
int triangleX = nextLocationX - coorX;
int triangleY = nextLocationY - coorY;
//if too near the coordinates of the destination changes
if (Math.abs(triangleX) <= Math.abs(speedX) || Math.abs(triangleY) <= Math.abs(speedY))//setting the new target
{
//setting the new destinatio
int randInt;
for (;;)//I don't want the the new destination to be that same spot
{
randInt= randGen.nextInt(appletX);
if (randInt != nextLocationX)
{
nextLocationX = randInt + radius;
break;
}
}
for (;;)
{
randInt = randGen.nextInt(appletY);
if (randInt != nextLocationY)
{
nextLocationY = randInt + radius;
break;
}
}
//calculating the change of the circle's X and Y coordinates
triangleX = nextLocationX - coorX;
triangleY = nextLocationY - coorY;
speedX = ((double)(speed * triangleX) / (Math.sqrt (Math.pow(triangleX, 2) + Math.pow(triangleY, 2))));
speedY = ((double)(speed * triangleY) / (Math.sqrt (Math.pow(triangleX, 2) + Math.pow(triangleY, 2))));
}
//the realCoor variables are from type double
//they are the exact coordinates of the circle
//If I only use integers, the circle almost
//never reaches it's destination
//unless the change of the coordinates gets calculated
//after every time they change
realCoorX = realCoorX + speedX;
realCoorY = realCoorY + speedY;
coorX = (int)Math.round(realCoorX);
coorY = (int)Math.round(realCoorY);
}
I suspect that the problem is in the calculation of the change of the coordinates.
For me this sounds like a Aliasing problem. You would have the same problem if you draw(!) a line that is not aligned with the coordinate axis. As you know, i.e. diagonal lines need "half filled" pixels to look smooth.
Solution for you would be (depending on the technology for rendering) to use floating point position calculation.