I am making a simple platform game in Libgdx... in which I have made the player to move left, move right and jump. The code works fine on Desktop but on Android devices, Jump is not fired when the player moves left or right. It looks strange. Here is my code...
private void updatePlayerForUserInput(float deltaTime)
{
// check input and apply to velocity & state
if ((Gdx.input.isKeyPressed(Keys.SPACE) || isTouched(0.87f, 1,0,1f)) && world.player.grounded)
{
world.player.velocity.y += world.player.JUMP_VELOCITY;
world.player.state =2;
world.player.grounded = false;
}
if (Gdx.input.isKeyPressed(Keys.LEFT) || Gdx.input.isKeyPressed(Keys.A) || isTouched(0, 0.1f,0,1f))
{
world.player.velocity.x -=world.player.MAX_VELOCITY;
if (world.player.grounded)
world.player.state =1;
world.player.facesRight = false;
}
if (Gdx.input.isKeyPressed(Keys.RIGHT) || Gdx.input.isKeyPressed(Keys.D) || isTouched(0.2f, 0.3f,0,1f))
{
world.player.velocity.x =world.player.MAX_VELOCITY;
if (world.player.grounded)
world.player.state =1;
world.player.facesRight = true;
}
}
private boolean isTouched(float startX, float endX , float startY, float endY)
{
// check if any finge is touch the area between startX and endX
// startX/endX are given between 0 (left edge of the screen) and 1 (right edge of the screen)
for (int i = 0; i < 2; i++)
{
float x = Gdx.input.getX() / (float) Gdx.graphics.getWidth();
float y = Gdx.input.getY() / (float) Gdx.graphics.getHeight();
if (Gdx.input.isTouched(i) && (x >= startX && x <= endX) && (y>=startY && y<= endY))
{
return true;
}
}
return false;
}
I took the idea from the demo platform game SuperKoalio by mzencher at
https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/superkoalio/SuperKoalio.java
Please suggest
This code:
float x = Gdx.input.getX() / (float) Gdx.graphics.getWidth();
float y = Gdx.input.getY() / (float) Gdx.graphics.getHeight();
Is always getting the x/y from the first active touch. You need to check the "i'th" active touch. Like this:
for (int i = 0; i < 20; i++) {
if (Gdx.input.isTouched(i)) {
float x = Gdx.input.getX(i) / (float) Gdx.graphics.getWidth();
float y = Gdx.input.getY(i) / (float) Gdx.graphics.getHeight();
if ((x >= startX && x <= endX) && (y>=startY && y<= endY)) {
return true;
}
}
return false;
Also, you should probably iterate through all 20 possible touch points, since up to 20 touch points can be tracked by the hardware. (Try putting three fingers in the "jump" region and then add a fourth finger in the "move left" region.)
Related
I am currently generating an isometric map which should allow some sprites to move randomly within its bounds. My sprites, or 'humans' do move within a specified constraint however it is not the correct boundaries I wish to set it to. Below is my code.
public class Human implements Entity {
private int[][] map;
public static final int TILE_WIDTH = 34;
public static final int TILE_HEIGHT = 34;
private int min = 100;
private int max = 200;
private Texture img;
// position variable
private Vector2 pos;
private float time;
public Human() {
img = new Texture(Gdx.files.internal("humanFF.png"));
// coordinates of human initial position
pos = new Vector2(9, 220);
// for locking movement if need be.
time = 2;
map = randomGenerator();
}
#Override
public void render(SpriteBatch batch) {
batch.draw(img, pos.x, pos.y);
}
#Override
public void update(float delta) {
time += delta;
Random rand = new Random();
int upperbound = 2;
double double_random = rand.nextDouble(upperbound);
// lock human, can only move once every 2 secs.
if (time > 0) {
move();
time = 0;
}
}
private void move() {
/** Calculation **/
for (int row = map.length - 1; row >= 0; row--) {
for (int col = map.length - 1; col >= 0; col--) {
float x = (col - row) * (TILE_WIDTH / 2f - 2);
float y = (col + row) * (TILE_HEIGHT / 4f);
}
}
// after calculation, mapWidth is 525 pixels.
int mapWidth = map.length * (TILE_WIDTH / 2 - 2);
// after calculation, mapHeight is 280 pixels.
int mapHeight = map.length * (TILE_HEIGHT / 4);
// Calculate the minimum and maximum x-coordinates.
float minX = 0;
float maxX = mapWidth - TILE_WIDTH;
if (maxX < 0) {
maxX = 0;
}
// max-x coordinate is 491.0. min-x coordinate is 0.0.
// Calculate the minimum and maximum y-coordinates.
float minY = 0;
float maxY = mapHeight - TILE_HEIGHT;
if (maxY < 0) {
maxY = 0;
}
// check the position of human against map boundaries
if (pos.x < minX) {
pos.x = minX;
} else if (pos.x > maxX) {
pos.x = maxX;
}
if (pos.y < minY) {
pos.y = minY;
} else if (pos.y > maxY) {
pos.y = maxY;
}
// min-y coordinate is 0.0, max-y coordinate is 246.0.
// a variable to store a random generated value between 100 and 200.
int a = (int) (Math.random() * (max - min + 1) + min);
float newX = pos.x;
float newY = pos.y;
// move up
if (a <= 125) {
newX -= 15;
newY += 8.5;
}
// move down
else if (a <= 150 && a > 125) {
newX += 15;
newY -= 8.5;
}
// move left
else if (a <= 175 && a > 150) {
newX -= 15;
newY -= 8.5;
}
// move right
else if (a <= 200 && a > 175) {
newX += 15;
newY += 8.5;
}
if (newX >= minX && newX <= maxX && newY >= minY && newY <= maxY) {
pos.x = newX;
pos.y = newY;
}
}
public int[][] randomGenerator() {
Random r = new Random();
int Size = r.nextInt(35, 36);
int[][] map = new int[Size][Size];
for(int row = 0; row < map.length; row++) {
for(int col = 0; col < map.length; col++) {
int Number = r.nextInt(10);
if(Number == 0) {
map[row][col] = 0;
} else if (Number == 1) {
map[row][col] = 1;
}
else if (Number == 2) {
map[row][col] = 2;
}
else if (Number == 3) {
map[row][col] = 3;
}
else if (Number == 4) {
map[row][col] = 4;
}
else if (Number == 5) {
map[row][col] = 5;
}
else if (Number < 8) {
map[row][col] = 6;
}
else {
map[row][col] = 7;
}
}
}
map[0][0] = 1;
return map;
}
}
Based on the above, I am generating a random value which defines the movement of my 'humans' thus adding or subtracting from their x and y positions. In my attempt to tackle the problem of these sprites moving outside of my isometric map, I tried to calculate my mapWidth, mapHeight, min-x, max-x, min-y and max-x and then checking the position of my human against these boundaries to determine their movement.
Although these sprites now move within a constraint, it is not same dimension as my isometric map, but are now constrained to a rectangular-shaped boundary. How do I modify my code so that the sprites only move within the isometric map I have generated?
Below is a photo for visualisation.
The coordinate system you use for Human enties is ordinary orthogonal, you don't map these coordinates to an isometric view but you -have to- map them onto the isometric background. Screen coordinate system is basically different from the isometric one. When you render you need to map coordinates so that
(0,0)-> left corner
(0,maxY)->top corner
(maxX,maxY)->right corner
(maxX,0)->bottom corner
See here for to and back(map screen touch events to the map etc) conversion LibGdx render a sprite on top of a isometric tile
I'm trying to make a 3D camera around a player on a game made with LWJGL3.
With the mouse scroll wheel you'll be able to zoom on the player.
How my function should be ?
How I query every event the mousewheel value.
glfwSetScrollCallback(window.getWindowHandle(), (windowHandle, xoffset, yoffset) -> {
currentMouseWheel.x = xoffset;
currentMouseWheel.y = yoffset;
});
My function to get Scroll delta based on the previous call :
(PS : input is called each gameLoop)
public void input(Window window) {
dMouseWheel.x = 0;
dMouseWheel.y = 0;
if (inWindow) {
double dx = currentMouseWheel.x - previousMouseWheel.x;
double dy = currentMouseWheel.y - previousMouseWheel.y;
if (dx != 0) {
dMouseWheel.x = (float) dx;
}
if (dy != 0) {
dMouseWheel.y = (float) dy;
}
}
previousMouseWheel.x = currentMouseWheel.x;
previousMouseWheel.y = currentMouseWheel.y;
}
xoffset and yoffset are never equals to 0.
I have to make big impulse on the scrollwheel to see the delta change.
What should I do ?
Can you give me an example ?
UPDATE : I found out !
How to do it :
First of all set 2 vectors variables :
private Vector2d currentMouseWheel;
private Vector2f dMouseWheel;
Then in your Scroll callback :
glfwSetScrollCallback(window.getWindowHandle(), (windowHandle, xoffset, yoffset) -> {
currentMouseWheel.x = xoffset;
currentMouseWheel.y = yoffset;
});
Then each game loop iteration, you call a function to update it
public void input() {
dMouseWheel.x = 0;
dMouseWheel.y = 0;
if (inWindow) {
dMouseWheel.x = (float) currentMouseWheel.x;
dMouseWheel.y = (float) currentMouseWheel.y;
}
currentMouseWheel.x = 0;
currentMouseWheel.y = 0;
}
Then you'll have dMouseWheel with the correct Scroll delta !
Let's first start off with what I am trying to do. I would like to be able to take PNG file with a transparent background and find anywhere from 90 to 360 points along the edge of the subject of the image. Here is a rough example of what I mean. Given this image of Mario and Yoshi:
I want to make a circle that is centered at the center of the image with a diameter slightly larger than the largest side of the image to serve as a reference. Then, I want to go around the circle at set intervals, and trace a line towards the center until it hits a non-transparent pixel. Here is what that would look like:
I have attempted to implement this a few different times, all of which failed, and I was hoping to get some guidance or insight as to what I am doing wrong. Here is an image of the math I am using behind the code (sorry if the quality is not great, I don't have a scanner):
The Line 1 is either the top, bottom, left or right edge of the image, and Line 2 goes through the center of the circle at the given angle. The point where lines 1 and 2 intersect should be on the edge of the image, and is where we should start looking for the edge of the image's subject.
Here is the code that I came up with from this idea. I did it in Java because BufferedImage is really easy to use, but I am going to translate this over to C# (XNA) for the final product.
public class Mesh {
private int angleA, angleB, angleC, angleD;
private BufferedImage image;
private Point center;
public ArrayList<Point> points = new ArrayList<>();
public Mesh(BufferedImage image) {
center = new Point(image.getWidth() / 2, image.getHeight() / 2);
angleA = (int) (Math.atan(center.y / center.x) * (180 / Math.PI));
angleB = 180 - angleA;
angleC = 180 + angleA;
angleD = 360 - angleA;
this.image = image;
for(int angle = 0; angle <= 360; angle+=4){
Point point = getNext(angle);
if(point != null) points.add(point);
}
}
private Point getNext(int angle) {
double radians = angle * Math.PI / 180;
double xStep = Math.cos(radians);
double yStep = Math.sin(radians);
int addX = angle >= 90 && angle <= 270 ? 1 : -1;
int addY = angle >= 0 && angle <= 180 ? 1 : -1;
double x, y;
if (xStep != 0) {
double slope = yStep / xStep;
double intercept = center.y - (slope * center.x);
if (angle >= angleA && angle <= angleB) {
y = 0;
x = -intercept / slope;
} else if (angle > angleB && angle < angleC) {
x = 0;
y = intercept;
} else if (angle >= angleC && angle <= angleD) {
y = image.getHeight() - 1;
x = (y - intercept) / slope;
} else {
x = image.getWidth() - 1;
y = slope * x + intercept;
}
} else {
x = center.x;
y = angle <= angleB ? 0 : image.getHeight();
}
if (x < 0) x = 0;
if (x > image.getWidth() - 1) x = image.getWidth() - 1;
if (y < 0) y = 0;
if (y > image.getHeight() - 1) y = image.getHeight() - 1;
double distance = Math.sqrt(Math.pow(x - center.x, 2) + Math.pow(y - center.y, 2));
double stepSize = Math.sqrt(Math.pow(xStep, 2) + Math.pow(yStep, 2));
int totalSteps = (int) Math.floor(distance / stepSize);
for (int step = 0; step < totalSteps; step++) {
int xVal = (int) x;
int yVal = (int) y;
if(xVal < 0) xVal = 0;
if(xVal > image.getWidth() -1) xVal = image.getWidth() -1;
if(yVal < 0) yVal = 0;
if(yVal > image.getHeight()-1) yVal = image.getHeight() -1;
int pixel = image.getRGB(xVal, yVal);
if ((pixel >> 24) == 0x00) {
x += (Math.abs(xStep) * addX);
y += (Math.abs(yStep) * addY);
} else {
return new Point(xVal, yVal);
}
}
return null;
}
}
The algorithm should be returning all positive points that are all ordered in counterclockwise rotation (and non-overlapping) but I have failed to get the desired output (this being my most recent attempt) so just to restate the question, is there a formalized way of doing this, or can someone find the mistake I made in my logic. For visual reference, the Mario and Yoshi Traced image is sort of what the final output should look like, but with many more points (which would give more detail to the mesh).
I'm using java with slick2d library and trying to move tile by tile with dynamic speed. I have tried a couple methods but none of them can move with dynamic speed between the tiles. Can someone help me with that and give some examples?
edit:
this two methods have I tried
move with out delta
movementSpeed = 2;
//decide direction
if(targetX != x)
{
animation.update(delta);
if(originalX < targetX)
x += movementSpeed;
else if(originalX > targetX)
x -= movementSpeed;
}
if(targetY != y)
{
animation.update(delta);
if(originalY < targetY)
y += movementSpeed;
else if(originalY > targetY)
y -= movementSpeed;
}
lerp
public static float lerp(float start, float stop, float t)
{
if (t < 0)
return start;
return start + t * (stop - start);
}
public void move(long delta)
{
if (procentMoved == 0)
{
if (getSpeed(targetX, targetY) != 0)
{
movementSpeed = getSpeed(targetX, targetY);
} else
{
targetX = originalX;
targetY = originalY;
}
}
if (procentMoved < 1)
{
animation.update(delta);
// movementSpeed = getSpeed(targetX, targetY);
procentMoved += movementSpeed;
} else if (procentMoved > 1)
{
animation.update(delta);
//TODO fix bouncing bug
procentMoved = 1;
}
+ movementSpeed);
x = lerp(originalX, targetX, procentMoved);
y = lerp(originalY, targetY, procentMoved);
if (x == targetX)
;
originalY = x;
if (y == targetY)
;
originalY = y;
}
It seems as if this could be your issue. Your if statements are just closing and not really doing its part. Also, you're variables are mixed up as well.
if (x == targetX)
; // This will skip the If statement
originalY = x;
if (y == targetY)
; // This will skip the If statement
originalY = y;
}
In all reality you're saying
orginalY = x; // Y = X?
orginalY = y; // Y = Y
Please do not take this to heart. I'm still having this issue as well, however I'm having to do some corrections and auto placements in order for this to work correctly.
I'm making a chess game in Java, and testing to make sure there are no pieces blocking the path of the piece being moved. The piece moves from (srcX,srcY) to (dstX,dstY).
I've written this code which checks if there are any obstructions for a rook:
if(dstY == srcY) {
// No change on Y axis, so moving east or west
if(dstX > srcX) {
// Moving east
// Test every cell the piece will pass over
for(int x = srcX+1; x < dstX; x++) {
// Is the cell set?
if(isPiece(x, srcY)) {
return true;
}
}
} else {
// Must be moving west
// Test every cell the piece will pass over
for(int x = srcX-1; x > dstX; x--) {
// Is the cell set?
if(isPiece(x, srcY)) {
return true;
}
}
}
} else if(dstX == srcX) {
// No change on X axis, so moving north or south
if(dstY > srcY) {
// Moving north
// Test every cell the piece will pass over
for(int y = srcY+1; y < dstY; y++) {
// Is the cell set?
if(isPiece(srcX, y)) {
return true;
}
}
} else {
// Must be moving south
// Test every cell the piece will pass over
for(int y = srcY-1; y > dstY; y--) {
// Is the cell set?
if(isPiece(srcX, y)) {
return true;
}
}
}
}
but it's a bit big and I'm sure it can be simplied.. any ideas?
ps, this is ONLY obstruction testing. I've already validated everything else.
Once you've tested for direction, you can set dx, dy values (e.g. dx=1, dy=0 for east). Then you can have a single for loop for all cases and just increment x and y by dx and dy respectively at each iteration.
You can then simplify the direction checking into the following:
if dstY == srcY: dy = 0
else: dy = (dstY - srcY) / abs(dstY - srcY)
if dstX == srcX: dx = 0
else: dx = (dstX - srcX) / abs(dstX - srcX)
Code:
int dx, dy;
if (dstY == srcY) dy = 0;
else dy = (dstY - srcY) / Math.abs(dstY - srcY);
if (dstX == srcX) dx = 0;
else dx = (dstX - srcX) / Math.abs(dstX - srcX);
while (srcX != dstX || srcY != dstY) {
srcX += dx; srcY += dy;
if (isPiece(srcX, srcY))
return true;
}
return false;
Also beware that this code (and yours) will fail if the move is not horizontal, vertical or diagonal.
You could do something along these lines (untested as I don't have a compiler to hand):
int dx = 0;
int dy = 0;
if (dstX != srcX) {
dx = (dstX > srcX) ? 1 : -1;
} else if (dstY != srcY) {
dy = (dstY > srcY) ? 1 : -1;
}
int x = srcX + dx;
int y = srcY + dy;
while (x != dstX || y != dstY) {
if (isPiece(x, y)) return true;
x += dx;
y += dy;
}
First, write tests. Lots and lots of tests. That way you can be confident that you're simplifying without changing the meaning of the code.
Refactoring without unit tests is like walking a high wire without a safety net.
Nearly the same, but with for loops:
// move along x axis
for (int x = 1; x < Math.abs(srcX - dstX); x++) {
int curX = (srcX - dstX) < 0 ? srcX - x : srcX + x;
if (isPiece(curX, srcY))
return true;
}
// move along y axis
for (int y = 1; y <= Math.abs(srcY - dstY); y++) {
int curY = (srcY - dstY) < 0 ? srcY - y : srcY + y;
if (isPiece(srcX, curY))
return true;
}
My soultion would be: introduce a direction class, and then do the check in this style:
isBlocked(startPossition, direction, numberOfFields)
I have done a little example, using 3 Classes.
Direction - an enum to represent the 8 directions (2 horizontal, 2 vertical, 4 diagonal)
Position - the x and y value of an position
LinarMove - represent one linear Move(startPossition, direction, numberOfFields) and contains the isBlockedMethod
The Enum:
public enum Direction {
UP(0, 1),
DOWN(0, -1),
LEFT(1, 0),
RIGHT(-1, 0),
UP_LEFT(UP, LEFT),
UP_RIGTH(UP, RIGHT),
DOWN_LEFT(DOWN, LEFT),
DOWN_RIGHT(
DOWN, RIGHT);
private final int incrementX;
private final int incrementY;
private Direction(int incrementX, int incrementY) {
this.incrementX = incrementX;
this.incrementY = incrementY;
}
private Direction(Direction sub1, Direction sub2) {
this.incrementX = sub1.incrementX + sub2.incrementX;
this.incrementY = sub1.incrementY + sub2.incrementY;
}
public Position oneField(Position start) {
return new Position(start.getX() + this.incrementX, start.getY()
+ this.incrementY);
}
}
The purpuse of second constructor is only that it alowes to write the diagonal moves in a more readable way.
public class Position {
private final int x;
private final int y;
public Position(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public String toString() {
return "x:" + x + ", y:" + y;
}
}
The Move contains the isBlocked Method -- you can see how small it get, and how readable it become. At least there is no single direction related if statement left.
The name LinareMove sugget that there is possible an other kind of move for the knight.
public class LinearMove {
private final Position start;
private final Direction direction;
/** Length of the move. */
private final int numberOfFields;
public LinearMove(Position start, Direction direction, int numberOfFields) {
super();
this.start = start;
this.direction = direction;
this.numberOfFields = numberOfFields;
}
boolean isBlocked() {
Position pos = this.start;
for (int i = 0; i < (this.numberOfFields - 1); i++) {
pos = this.direction.oneField(pos);
if (isPiece(pos)) {
return true;
}
}
return false;
}
boolean isPiece(Position pos) {
//Dummy;
System.out.println(pos);
return false;
}
}
And this is how it works:
public static void main(String[] args) {
new LinearMove(new Position(1, 1), Direction.RIGHT, 3).isBlocked();
}
You maybe noticed, that the knights move is some kind of probem. With this soultion you could model it in two ways:
- 4 special Directions
- an other kind of move class (this is the more cleaner way, because you could always return true, in the isBockedMethod)