Moving a body to specific point [Box2D , Libgdx] - java

I'm trying to make a simple magnet effect when my character is near a coin this should move to his position
I have this:
if(Mycharacter.position.x +2 >= position.x) //position = coin position
{
body.setTransform(Mycharacter.position.x, Mycharacter.position.y, 0);
}
This is close to what I want but I need to be able to see the movement of the coin to my character.
I'm still very new to Box2d and Libgdx so if possible keep it really simple guys, it doesn't help I'm terrible on physics. Thanks in advance.

I found the answer:
if("Any condition")
{
body.setLinearVelocity((Character.position.x - position.x) * Velocity, (Character.position.y - position.y)* Velocity);
}
Reminder that this is just the simplest way to achieve what I wanted. I'm sure there a more proper ways to do it.

You can do this:
1. Compute vector from you to coin (vx = coin.x - player.x, same for y)
2. Compute the vectors's distance (using MathUtils.sqrt(vx*vx+vy*vy))
3. If distance is shorter than magnet range, then reduce the distace.
4. recompute new vector from player to coin (vx *= (newDistance/oldDistance))
5. update coin'S position

Related

How to make the same speed between sets of points? Using lerp

So I'm making a game where a unit follows a path set by the player. The way I code this is regularly setting points, and then making the unit follow through each of those points. Here's the code for the movement:
Vector2 goal = unitPath.getVertex().cpy();
if(alpha >= 1){
unitPath.nextVertex();
goal = unitPath.getVertex();
lastPosition = new Vector2 (getX() + getOriginX(), getY()+getOriginY());
alpha = 0;
}
System.out .println(alpha);
alpha += dt * speed;
Vector2 position = lastPosition.cpy();
if(goal != null){
position.lerp(goal, alpha);
this.centerAtPosition(position.x, position.y);
}
Here's the code for how each point is set:
Vector2 screenCoord = BattleScreen.getViewport().unproject(new Vector2(screenX, screenY));
if (new Vector2(screenCoord.x - currentVert.x, screenCoord.y - currentVert.y).len() > diagonal())
{
unitPath.addVertices(screenCoord.x, screenCoord.y);
currentVert = screenCoord.cpy();
}
The problem I was having was that between every two points, the speed with which the unit crosses the two points changes. This is because the speed of the mouse moving changes the distance between each point. I want to make it so that it has the same speed between each point.
So my question is two-fold:
how do I make the speed the same between each point?
is there a better of doing this then the way I'm doing right now?
Somehow I find your code hard to follow, but point is that you have your horizontal speed (i.e. Vx) and vertical speed (Vy). Vx^2 + Vy^2 must be equal to V^2, where V is total speed.
So after you calculate your speed you should "normalize" it. Calculate total speed you have and compare it to speed you want to achieve. I.e. you calculated total speed 4, but you want your units to move at speed 2, then it means that your units are moving twice faster so you have to divide your Vx and Vy speed components with 2.
Hope that this makes some sense to you.

Smooth moving LibGdx

I'm trying to make this thing:
When user press a key once, the sprite smoothly moves on some pixels. But it just "teleporting" to the position. Here is the code:
int co = 0;
Vector2 ppos=new Vector2(x,y);
if (Gdx.input.isKeyJustPressed(Keys.A)){
while (co < 33) {
batch.begin();
ppos.y += Gdx.graphics.getDeltaTime()*5;
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.draw(Splayer, ppos.x, ppos.y); //Splayer is a sprite
batch.end();
co++;
out(co+"");
}
}
What am I doing wrong?
I will deconstuct your code:
while (co < 33) {
So this will loop 33 times since you have co = 0 and increment co each loop.
ppos.y += Gdx.graphics.getDeltaTime()*5;
You increment the y position by your framerate * 5. so something like 5 * 0.02 * 33 is happening which makes 3.3. Nothing wrong with that but it is kinda unconventional to use a loop for that. Since doing y = 5 * framerate * 33 would be the same, easier and faster.
It depends on what you want to end up with but basically "we" do something like this.
//Have position variable
private Vector2 position;
//Have a speed variable
private float speed;
//direction variable
private Vector2 direction;
//have a velocity variable (direction * speed)
private Vector2 velocity;
velocity should be direction * speed and the velocity can then be added each frame to the position. let's say we want to move up. The direction would be (0,1) (the direction should never exceed the length of 1, if it does then normalize the vector direction.nor(). This will make sure it is 1 long so multiplying this will results in the same speed in any direction.
direction = new Vector2(0,1);
//an easy way to make it go 45 degree up/right would be
direction = new Vector2(1,1);
direction.nor(); //normalized to 1 long.
//now we can make the velocity
velocity = direction.cpy().scl(speed); //we copy the vector first so we are not changing the direction vector.
//If you want to have this framerate independent
velocity = direction.cpy().scl(speed * Gdx.graphics.getDeltatime);
Now we just add velocity to position. Basic math (1, 1) + (0, 1) = (1 ,2). Yes that is how simple Vectors are. original pos (0, 0)plus direction multiplied by speed+ (0 * 10, 1 * 10) = (0, 10)`. So to add velocity to position in code:
position.add(velocity);
batch.draw(textures, position.x, position.y);
This would be my way of doing it, I find this very easy.
What you are doing wrong is generating a new Vector each game loop when you press "A". You should think twice about having the new keyword in your loop. It is better the change you vector or reset it since it the old one will be lost in memory and needs to be collected. One Vector will not get you into trouble but 1 Texture that needs manual disposing will, learn it the right way.
Other then that, why have a variable named ppos? Why not just position or patientPosition or palaeoanthropologyPosition or whatever the "p" stands for. You are only required to type it once in most IDE because intellisense will pick it up. So make your and others life easier by clearly defining variables.
you should use Scene2D for smooth movement.

How to create whirlpool/vortex effect?

Im trying to make a Vortex effect on a Circle Body that is a Sensor.
I've been looking for this and all examples i look for are in C++ or Objective C and i dont seem to translate them well.
when my objects collition, it calls beginContact(..) and it sets a flag so that i can call bodyToUpdate.applyForce(...);
public void beginContact(Contact contact) {
setColliding(true);
}
//updating collition every frame
public void act(){
if (colliding) {
ball.getBody().applyForce(....);
}
how to calculate the amount of force to apply every frame to make it a vortex?
Edit:
so i now have the object going straight to the center of the vortex, but no "spin"
public void act() {
if (colliding) {
ball.getBody().setLinearVelocity(0, 0);
ball.getBody().applyForce((portal.getBody().getPosition().x - ball.getBody().getPosition().x) * i,
(portal.getBody().getPosition().y - ball.getBody().getPosition().y) * i,
ball.getBody().getPosition().x, ball.getBody().getPosition().y, true);
i++;
} else
i = 10;
}
If by "spin" you mean that the falling object would move along a curve or a spiral, rather then changing the direction of movement immediately towards the black hole, there is an easy fix for that.
ball.getBody().setLinearVelocity(0, 0);
This completely stops the current movement of the body. I would start by removing that line. Also, for better realistic behaviour, you can follow the proper formula to compute attractive force, which goes something like this:
force = mass1 * mass2 * [some constant] / (distance ^ 2)
When you have the vector from your body towards the black hole (computed as black hole position - body position), the length of the vector is the distance, and after normalizing and multiplying by the force, you have the desired forceX and forceY force vector that needs to be applied to the body each update, as long as it stays in range of the hole.
However this formula will cause the force to grow to infinity as body moves closer to the hole, so you could try changing to linear conversion (closest = 1, farest = 0) if that causes any trouble.
force = mass1 * mass2 * [some constant] * ( (maxDistance - distance) / maxDistance )
You want to implement a tangential force with a magnitude that increases towards the center of the vortex.
Here's some pseudocode.
radialVector = objectPosition - vortexPosition;
tangentialVector = radialVector.perpendicularVector();
if (radialVector.length() < vortexRadius) {
// Swirl faster when near the center of the vortex.
// Max tangential force when distance from center is 0.
// Min tangential force when distance from center is vortexRadius.
forceMagnitude = map(radialVector.length(), vortexRadius, 0, minTangentialForce, maxTangentialForce);
force = forceMagnitude * tangentialVector.normalize();
object.applyForce(force);
}
Here's an image that shows the vector components:
To create a whirlpool effect there should be increasing radial (Fr) and tangential (Ft) forces as the object moves closer to the center.

How to make a hitbox?

I'm making a game similar to mario and I've got this map generated by arrays and images. But my problem is that I don't know how to make a hitbox system for all the tiles. I've tried to have a position based collision system based on your position on the map
like this
if(xpos > 10*mapX && xpos < 14 * mapX){
ypos -= 1;
}
But I don't want to that for every wall or hole.
So is there a way to check in front, below and above the character to see if there is a hitbox there and if there is you cant move that direction or fall?
Thank you
If it's a simple 2D game, I'd suggest dividing the map into square tiles. You could store the map in the memory as a two dimensional array and during each frame check tiles adjacent to the player. Of course he can occupy as much as 4 tiles during movement, but it makes you check only up to 12 positions, which can be easily done.
Further collision checking can be done easily using image position and dimension.
Remember that there is no need to check if a static object (environment) is colliding with something, you just need to check objects that have made a move since last frame, i.e. the player and sprites.
EDIT:
Let's say you've got the following section of map (variable map):
...
.pe
ooo
where
. = nothing
p = player
o = floor
e = enemy
you also have the pair (x, y) representing tile indices (not exact position) of the player. In this case you have to do something like this:
if ("o".equals(map[y + 1, x + 1]))
//floor is under
if ("e".equals(map[y, x + 1]))
//enemy is on the right
if ("o".equals(map[y - 1, x]))
//floor is above us
If any of these conditions are met, you have to check image positions and handle collisions.
Note: clicked submit way after the last post was made...
As Mateusz says a 2D array is best for this type of game:
e.g. using chars:
0123456789012
0 ==
1 * ===
2===== =======
So in this case tileMap[8][1] == '*'. You'd probably be best using an enumeration instead of chars though e.g. Tile.SPRING for a Sonic style spring board.
If your map was made up of regular sized tiles you could say:
int xInFrontOfPlayer = playerX + PLAYER_WIDTH;
int xBehindPlayer = playerX - PLAYER_WIDTH;
Tile tileInFrontOfPlayer = getTileAtWorldCoord(xInFrontOfPlayer, playerY);
Tile tileBehindPlayer = getTileAtWorldCoord(xBehindPlayer, playerY);
...
public Tile getTileAtWorldCoord(int worldX, worldY) {
return tileMap[worldX / TILE_WIDTH][worldY / TILE_HEIGHT];
}
Where TILE_WIDTH and TILE_HEIGHT are the dimensions of your tiles in pixels. Then use similar math for yAbovePlayer and yBelowPlayer.
You might then have some logic in your game loop:
if user is pressing the "go right" key:
if the tile to the right is Tile.SPACE:
move player right
else if the tile to the right is Tile.WALL:
don't do anything
if the tile below is Tile.SPACE:
fall

How to have a "Camera" only show a portion of a loaded area

I'm having a little problem with figuring something out (Obviously).
I'm creating a 2D Top-down mmorpg, and in this game I wish the player to move around a tiled map similar to the way the game Pokemon worked, if anyone has ever played it.
If you have not, picture this: I need to load various areas, constructing them from tiles which contain an image and a location (x, y) and objects (players, items) but the player can only see a portion of it at a time, namely a 20 by 15 tile-wide area, which can be 100s of tiles tall/wide. I want the "camera" to follow the player, keeping him in the center, unless the player reaches the edge of the loaded area.
I don't need code necessarily, just a design plan. I have no idea how to go about this kind of thing.
I was thinking of possibly splitting up the entire loaded area into 10x10 tile pieces, called "Blocks" and loading them, but I'm still not sure how to load pieces off screen and only show them when the player is in range.
The picture should describe it:
Any ideas?
My solution:
The way I solved this problem was through the wonderful world of JScrollPanes and JPanels.
I added a 3x3 block of JPanels inside of a JScrollPane, added a couple scrolling and "goto" methods for centering/moving the JScrollPane around, and voila, I had my camera.
While the answer I chose was a little more generic to people wanting to do 2d camera stuff, the way I did it actually helped me visualize what I was doing a little better since I actually had a physical "Camera" (JScrollPane) to move around my "World" (3x3 Grid of JPanels)
Just thought I would post this here in case anyone was googling for an answer and this came up. :)
For a 2D game, it's quite easy to figure out which tiles fall within a view rectangle, if the tiles are rectangular. Basically, picture a "viewport" rectangle inside the larger world rectangle. By dividing the view offsets by the tile sizes you can easily determine the starting tile, and then just render the tiles in that fit inside the view.
First off, you're working in three coordinate systems: view, world, and map. The view coordinates are essentially mouse offsets from the upper left corner of the view. World coordinates are pixels distances from the upper left corner of tile 0, 0. I'm assuming your world starts in the upper left corner. And map cooridnates are x, y indices into the map array.
You'll need to convert between these in order to do "fancy" things like scrolling, figuring out which tile is under the mouse, and drawing world objects at the correct coordinates in the view. So, you'll need some functions to convert between these systems:
// I haven't touched Java in years, but JavaScript should be easy enough to convey the point
var TileWidth = 40,
TileHeight = 40;
function View() {
this.viewOrigin = [0, 0]; // scroll offset
this.viewSize = [600, 400];
this.map = null;
this.worldSize = [0, 0];
}
View.prototype.viewToWorld = function(v, w) {
w[0] = v[0] + this.viewOrigin[0];
w[1] = v[1] + this.viewOrigin[1];
};
View.prototype.worldToMap = function(w, m) {
m[0] = Math.floor(w[0] / TileWidth);
m[1] = Math.floor(w[1] / TileHeight);
}
View.prototype.mapToWorld = function(m, w) {
w[0] = m[0] * TileWidth;
w[1] = m[1] * TileHeight;
};
View.prototype.worldToView = function(w, v) {
v[0] = w[0] - this.viewOrigin[0];
v[1] = w[1] - this.viewOrigin[1];
}
Armed with these functions we can now render the visible portion of the map...
View.prototype.draw = function() {
var mapStartPos = [0, 0],
worldStartPos = [0, 0],
viewStartPos = [0, 0];
mx, my, // map coordinates of current tile
vx, vy; // view coordinates of current tile
this.worldToMap(this.viewOrigin, mapStartPos); // which tile is closest to the view origin?
this.mapToWorld(mapStartPos, worldStartPos); // round world position to tile corner...
this.worldToView(worldStartPos, viewStartPos); // ... and then convert to view coordinates. this allows per-pixel scrolling
mx = mapStartPos[0];
my = mapStartPos[y];
for (vy = viewStartPos[1]; vy < this.viewSize[1]; vy += TileHeight) {
for (vx = viewStartPos[0]; vx < this.viewSize[0]; vy += TileWidth) {
var tile = this.map.get(mx++, my);
this.drawTile(tile, vx, vy);
}
mx = mapStartPos[0];
my++;
vy += TileHeight;
}
};
That should work. I didn't have time to put together a working demo webpage, but I hope you get the idea.
By changing viewOrigin you can scroll around. To get the world, and map coordinates under the mouse, use the viewToWorld and worldToMap functions.
If you're planning on an isometric view i.e. Diablo, then things get considerably trickier.
Good luck!
The way I would do such a thing is to keep a variable called cameraPosition or something. Then, in the draw method of all objects, use cameraPosition to offset the locations of everything.
For example: A rock is at [100,50], while the camera is at [75,75]. This means the rock should be drawn at [25,-25] (the result of [100,50] - [75,75]).
You might have to tweak this a bit to make it work (for example maybe you have to compensate for window size). Note that you should also do a bit of culling - if something wants to be drawn at [2460,-830], you probably don't want to bother drawing it.
One approach is along the lines of double buffering ( Java Double Buffering ) and blitting ( http://download.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html ). There is even a design pattern associated with it ( http://www.javalobby.org/forums/thread.jspa?threadID=16867&tstart=0 ).

Categories