I want to change the height of my texture to a random height (with a specified range), and I almost figured out how, but the problem I have is that the texture (tower) is now above the ground. I want to stretch the texture while it remains on the same position, but changes height length.
I have a Tower class and a Scrollable class. In the Tower class I generate a random height in the reset method, but the problem is that I don't know what exactly I have to add or write to put the texture on the correct position (so that it isn't above the ground).
Here is the Tower class:
public class Tower extends Scrollable {
private Random r;
// When Tower's constructor is invoked, invoke the super (Scrollable)
// constructor
public Tower(float x, float y, int width, int height, float scrollSpeed) {
super(x, y, width, height, scrollSpeed);
// Initialize a Random object for Random number generation
r = new Random();
}
#Override
public void reset(float newX) {
// Call the reset method in the superclass (Scrollable)
super.reset(newX); // newX
// Change the height to a random number
Random r = new Random();
int low = 0;
int high = 15;
int result = r.nextInt(high-low) + low;
height = result;
}
}
And here's the Scrollable class:
public class Scrollable {
protected Vector2 position;
protected Vector2 velocity;
protected int width;
protected int height;
protected boolean isScrolledLeft;
public Scrollable(float x, float y, int width, int height, float scrollSpeed) {
position = new Vector2(x, y);
velocity = new Vector2(scrollSpeed, 0);
this.width = width;
this.height = height;
isScrolledLeft = false;
}
public void update(float delta) {
position.add(velocity.cpy().scl(delta));
// If the Scrollable object is no longer visible:
if (position.x + width < 0) {
isScrolledLeft = true;
}
}
// Reset: Should Override in subclass for more specific behavior.
public void reset(float newX) {
position.x = newX;
isScrolledLeft = false;
}
public boolean isScrolledLeft() {
return isScrolledLeft;
}
public float getTailX() {
return position.x + width;
}
public float getX() {
return position.x;
}
public float getY() {
return position.y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
Maybe it's important to know that I have a GameRenderer class which has a drawTowers() method, which is then used in a render() method.
That's my drawTowers() method:
private void drawTowers() {
batcher.draw(AssetLoader.texture1, tower1.getX(), tower1.getY() + tower1.getHeight(),
tower1.getWidth(), midPointY - (tower1.getHeight()));
batcher.draw(AssetLoader.texture2, tower2.getX(), tower2.getY() + tower2.getHeight(),
tower2.getWidth(), midPointY - (tower2.getHeight()));
batcher.draw(AssetLoader.texture3, tower3.getX(), tower3.getY() + tower3.getHeight(),
tower3.getWidth(), midPointY - (tower3.getHeight()));
batcher.draw(AssetLoader.texture4, tower4.getX(), tower4.getY() + tower4.getHeight(),
tower4.getWidth(), midPointY - (tower4.getHeight()));
}
You are drawing the tower too high, you need to be adding half the height rather than the whole height.
Here in drawTowers():
batcher.draw(AssetLoader.texture1, tower1.getX(), tower1.getY() + tower1.getHeight() / 2, tower1.getWidth(), midPointY - (tower1.getHeight()));
Do the same for the other towers.
This may not be perfectly correct but it shouldn't be far off.
Related
I'm trying to see if a touch position collides with a Body and I'm not sure about the best way to implement it.
As of now, I have an Obstacle.java that draws a polygon-shaped body as a rectangle. It works fine to draw in the world, I just need to check for collisions.
Furthermore, I want to add some Sprite/Texture/Image to this body, so maybe it's better to check for collision between the sprite rather than the body, I'm not sure. So any pointers in the right direction would be helpful.
Obstacle.java
public class Obstacle{
public int x,y;
public Vector3 position;
public World world;
private Body body;
private BodyDef bodyDef;
private PolygonShape shape;
private float density = 1f;
private final float width = 360f;
private final float height = 20f;
Random r;
public Obstacle(World world) {
r = new Random();
this.world = world;
//rectangle
bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set( new Vector2( x + width / 2, y + height / 2));
float randomValue = (float)(0 + (540 - 0) * r.nextDouble());
shape = new PolygonShape();
shape.setAsBox( width / 2, height / 2 );
body = world.createBody(bodyDef);
body.createFixture(shape, density);
body.setTransform(randomValue,1160,0);
float angularVelocity;
if(r.nextInt(2)==0){
angularVelocity=-3;
}else{
angularVelocity=3;
}
body.setAngularVelocity(angularVelocity);
body.setLinearVelocity(0,-250);
}
public float getX() {
return position.x;
}
public float getY() {
return position.y;
}
public float getWidth() {
return 360 / GdxGame.PPM;
}
public float getHeight() {
return 20 / GdxGame.PPM;
}
public void render(SpriteBatch batch,float delta) {
}
public Boolean collidesWithPlayer(float touchX, float touchY){
return false;
}
}
The last method collidesWithPlayer was an effort from me to implement the detection, and in my Screen.java I have:
for(int i = 0; i < obstacles.size(); i++) {
if(obstacles.get(i).collidesWithPlayer(pointerX, pointerY)) {
hasDied=true;
}else{
isPaused=true;
}
}
I have created a 10x10 grid for a game, and now i am trying to get the image i have for the player to display inside one of the grid squares. I have a Game, Player and Draw class. in the Game class the x and y position of the player are set, in the Player class is where i set the values for the x and y position and create the bitmap. In the Draw class I create the grid and call it in the onDraw method. I was wondering how do I call the bitmap in the onDraw so that it will display? I dont know if this makes any sense but any help or tips would be good.
public class Game {
Bitmap image;
int x;
int y;
int height;
int width;
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
public int getX()
{
return x;
}
public int getY(){
return y;
}
public int getHeight(){
return height;
}
public int getWidth(){
return width;
}
}
public class Player extends Game {
public Player(Bitmap res, int w, int h, Context context){
image = res;
x = 300;
y = 300;
height = 300;
width = 300;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.sokobanplayer1);
}
}
public class Draw extends View {
Paint red = new Paint();
Paint green = new Paint();
int rectSide = 1000;
public Draw(Context context) {
super(context);
red.setColor(Color.RED);
green.setColor(Color.GREEN);
red.setStrokeWidth(8);
green.setStrokeWidth(8);
}
public void drawGrid(Canvas canvas) {
int width = canvas.getWidth();
int height = canvas.getHeight();
float startX = (width / 2) - (rectSide / 2);
float stopX = (width / 2) + (rectSide / 2);
float startY = (height / 2) - (rectSide / 2);
float stopY = (height / 2) + (rectSide / 2);
for (int i = 0; i < 1100; i += 100) {
float newY = startY + i;
canvas.drawLine(startX, newY, stopX, newY, green);
}
for (int i = 0; i < 1100; i += 100) {
float newX = startX + i;
canvas.drawLine(newX, startY, newX, stopY, green);
}
}
public void drawPlayer(Bitmap res, int w, int h, Context context){
Bitmap image = res;
int x = 300;
int y = 300;
int height = 300;
int width = 300;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.sokobanplayer1);
}
#Override
public void onDraw(Canvas canvas) {
drawGrid(canvas);
//canvas.getResources(image, x, y, null);
}
}
I am making a 2d rpg game in java and I have run into a problem. I can make the player move around the stage and I have rocks, trees, walls, etc. on the stage as well. I don't know how to detect the collision and make it to where the player can't move through the object. The code that reads map file and draws image on the canvas is as follows:
public void loadLevel(BufferedImage levelImage){
tiles = new int[levelImage.getWidth()][levelImage.getHeight()];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Color c = new Color(levelImage.getRGB(x, y));
String h = String.format("%02x%02x%02x", c.getRed(),c.getGreen(),c.getBlue());
switch(h){
case "00ff00"://GRASS Tile - 1
tiles[x][y] = 1;
break;
case "808080"://Stone -2
tiles[x][y] = 2;
break;
case "894627"://Dirt -3
tiles[x][y] = 3;
break;
case "404040"://Rock on Grass -4
tiles[x][y] = 4;
break;
case "00b700"://Tree -5
tiles[x][y] = 5;
break;
case"000000"://Wall -6
tiles[x][y] = 6;
break;
case "cccccc"://Rock on stone -7
tiles[x][y] = 7;
break;
default:
tiles[x][y] = 1;
System.out.println(h);
break;
}
}
}
}
And the player class is as follows:
public class Player {
private int x,y;
public int locx,locy;
private Rectangle playerR;
private ImageManager im;
public boolean up =false,dn = false,lt=false,rt=false,moving = false,canMove = true;
private final int SPEED =2;
public Player(int x, int y, ImageManager im){
this.x = x;
this.y = y;
this.im = im;
locx = x;
locy = y;
playerR = new Rectangle(x,y,16,16);
}
public void tick(){
if (up) {
if(canMove){
y -= SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
moving = true;
}
else{
y += 1;
canMove=true;
}
}
if (dn) {
y +=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if (lt) {
x -= SPEED;
locx = x;
locy = y;
moving = true;
}
if (rt) {
x+=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if(moving){
System.out.println("PLAYER\tX:"+locx+" Y:"+locy);
moving = false;
}
}
public void render(Graphics g){
g.drawImage(im.player, x, y, Game.TILESIZE*Game.SCALE, Game.TILESIZE*Game.SCALE, null);
}
}
I don't really know how to do collision, but i googled it and people said to make a rectangle for the player and all the objects that the player should collide with, and every time the player moves, move the player's rectangle. Is this the right way to do this?
EDIT EDIT EDIT EDIT
code for when collision is true:
if (rt) {
x+=SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
for(int i = 0;i<Level.collisions.size();i++){
if(intersects(playerR,Level.collisions.get(i))==true){
x-=SPEED;
locx = x;
playerR.setLocation(locx, locy);
}
}
moving = true;
}
And the intersects method is as follows:
private boolean intersects(Rectangle r1, Rectangle r2){
return r1.intersects(r2);
}
I'm going to focus on your tick method since that is where most of this logic is going. There are a couple changes here. Most notably, we only move the rectangle before checking for collisions. Then loop through all the collideable objects in your level. Once one is found, we reset our x and y and break out of the loop (no sense in looking at any of the other objects since we already found the one we collided with). Then we update our player position. By doing it this way, I centralized the code so it is not being repeated. If you ever see yourself repeating code, there is a pretty good chance that it can be pulled out to a common place, or to a method.
public void tick() {
if (up) {
y -= SPEED;
} else if (dn) {
y += SPEED;
} else if (lt) {
x -= SPEED;
} else if (rt) {
x += SPEED;
}
playerR.setLocation(x, y);
for (Rectangle collideable : Level.collisions) {
if (intersects(playerR, collideable)) {
x = locx;
y = locy;
playerR.setLocation(x, y);
break;
}
}
locx = x;
locy = y;
}
There are different ways to do that. As you talk about a "rpg" i think your view is Isometric (45° top down).
I would do the collision detection in pure 90° top down, as it is easier and, imho, more realistic.
We have 2 possibilities:
Move your Player to the next position. If there is a collision, reset his position.
Calculate the next position, if there would be a collision don't move.
If you want to have a "gliding" collision response, you have to check in which axis the collision will happen, and stop / reset movement for this axis only.
To have a more efficient collision detection only check near objects, which will possibly collide.
Do this by comparing a squared "dangerRadius" with the squared distance between your player and the object:
if ((player.x - object.x)² + (player.y - object.y)² <= dangerRadius²)
// Check for intersection
This will sort out most of the objects by using a simple calculation of:
2 subtractions
1 addition
3 multiplications (the ²)
1 compare (<=)
In your game you should sepparate the logic and the view. So basicly you don't detect, if the two images overlapp, but you check, if the objects in your logic overlap. Then you draw the images on the right position.
Hope this helps.
EDIT: Important: If you update your character, depending on the time between the last and this frame (1/FPS) you have to limit the max timestep. Why? Because if for some reason (maybe slow device?) the FPS are really low, it is possible, that the character moves verry far between 2 frames and for that he could go through an object in 1 frame.
Also if you simply reset the movement on collision or just don't move the distance between you and the object could be big for low FPS. For normal FPS and not to high movementspeed this won't happen/ be noticeable.
I personally am fairly new to Java, though I have worked with C# in the past. I am making a similar game, and for collision detection I just check the locations of the player and objects:
if (z.gettileX() == p.gettileX()){
if (z.gettileY() == p.gettileY()){
System.out.println("Collision!");
}
}
If the player (p) has equal X coordinates and Y coordinates to z(the bad guy), it will send this message and confirm that the two have, in fact, collided. If you can make it inherent in the actual class behind z to check if the coordinates a equal, you can create an unlimited number of in-game objects that detect collision and react in the same way, i.e. walls.
This is probably what your looking for. I've made this class spicificly for collision of multiple objects and for individual side collisions.
abstract class Entity {
private Line2D topLine;
private Line2D bottomLine;
private Line2D leftLine;
private Line2D rightLine;
private Rectangle rectangle;
private Entity entity;
protected boolean top;
protected boolean bottom;
protected boolean left;
protected boolean right;
protected int x;
protected int y;
protected int width;
protected int height;
public Entity(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
updateLinesAndRects();
}
public void updateLinesAndRects() {
topLine = new Line(x + 1, y, width - 2, 0);
bottomLine = new Line(x + 1, y + height, width - 2, height);
leftLine = new Line(x, y + 1, 0, height - 2);
rightLine = new Line(x + width, y + 1, 0, height - 2);
rectangle = new Rectangle(x, y, width, height)
}
public void setCollision(Entity entity) {
this.entity = entity;
top = isColliding(new Line2D[]{topLine, bottomLine, leftLine, rightLine});
bottom = isColliding(new Line2D[]{bottomLine, topLine, leftLine, rightLine});
left = isColliding(new Line2D[]{leftLine, topLine, bottomLine, rightLine});
right = isColliding(new Line2D[]{rightLine, topLine, bottomLine, leftLine});
}
public void updateBounds() {
if(top) y = entity.y + entity.height;
if(bottom) y = entity.y - height;
if(left) x = entity.x + entity.width;
if(right) x = entity.x - width;
}
public boolean isColliding() {
return rectangle.intersects(entity.rect);
}
private boolean isLinesColliding(Line2D[] lines) {
Rectangle rect = entity.getRectangle();
return lines[0].intersects(rect) && !lines[1].intersects(rect) && !lines[2].intersects(rect) && !lines[3].intersects(rect);
}
private Line2D line(float x, float y, float width, float height) {
return new Line2D(new Point2D.Float(x, y), new Point2D.Float(x + width, x + height));
}
public Rectangle getRectangle() {
return rectangle;
}
}
Example:
class Player extends Entity{
Entity[] entities;
public Player(int x, int y, int width, int height) {
super(x, y, width, height);
}
public void update() {
updateLinesAndRects();
for(Entity entity : entities) {
setCollision(entity);
if(top) system.out.println("player is colliding from the top!");
if(isColliding()) system.out.println("player is colliding!");
updateBounds(); // updates the collision bounds for the player from the entities when colliding.
}
}
public void setEntities(Entity[] entities) {
this.entities = entities;
}
}
I'm trying to make a roguelike in java to practice. This is my code to generate a floor (right now just a big room with wall tiles on the edge). I'm trying to set certain tiles in my tile array to either a wall tile or floor tile. Although when they leave the setTile method, they revert back to their value before entering the method. I'm going insane. Here's my code:
public Floor(int width, int height) {
this.tiles = new Tile[(width+1)*(height+1)];
this.width = width;
this.height = height;
generateTiles();
boolean test = false;
}
public Tile getTile(int x, int y)
{
return tiles[y * width + x];
}
public void setTile(int x, int y, Tile tile)
{
Tile tileToSet = getTile(x,y);
tileToSet = tile;
}
private void generateTiles() {
for (int i = 0; i < tiles.length; i++)
{
tiles[i] = new Tile();
}
//make the top wall
for (int i = 0; i<width;i++)
{
setTile(i,0,new WallTile());
}
}
}
Your setTile doesn't make sense. You're retrieving the tile which is currently at that position, storing it in a local variable tileToSet and then overwriting the value of that variable.
What you're trying to do is storing the given tile in the tiles array. Analogous to how getTile is implemented, you can do this with:
public void setTile(int x, int y, Tile tile)
{
tiles[y * width + x] = tile;
}
Note that this is not equivalent (but you seem to think it is) with:
public void setTile(int x, int y, Tile tile)
{
Tile tileToSet = tiles[y * width + x];
tileToSet = tile;
}
This code is setting the same variable twice and doing nothing with it.
public void setTile(int x, int y, Tile tile)
{
Tile tileToSet = getTile(x,y);
tileToSet = tile;
}
I think you want something like this:
public void setTile(int x, int y, Tile tile)
{
tiles[y * width + x] = tile;
}
That would change the value of what is stored in the tiles array to the supplied Tile object.
ya in Java when you pass an object into the function, the reference to that object is copied by value. What this means is you can't swap tile references.
What you'll need to do, is something like this:
public Floor(int width, int height) {
this.tiles = new Tile[(width+1)*(height+1)];
this.width = width;
this.height = height;
generateTiles();
boolean test = false;
}
public Tile getTile(int x, int y)
{
return tiles[y * width + x];
}
public void setTile(int x, int y, Tile tile)
{
tiles[y * width + x] = tile;//this works cuz it takes the ref from the array and assigns it the copy of the reference passed in
}
private void generateTiles() {
for (int i = 0; i < tiles.length; i++)
{
tiles[i] = new Tile();
}
//make the top wall
for (int i = 0; i<width;i++)
{
setTile(i,0,new WallTile());
}
}
}
Check out this article for explanation: http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
Look at your setTile method:
public void setTile(int x, int y, Tile tile)
{
Tile tileToSet = getTile(x,y);
tileToSet = tile;
}
You are getting the tile value at x,y and set it to a local variable (tileToSet), then set the tile value to the variable tileToSet. Of course it doesn't change the tile at x,y. tileToSet is just a reference to the value, it is never a reference to the array element.
replace with this:
public void setTile(int x, int y, Tile tile)
{
tiles[y * width + x] = tile;
}
and if you want to have a method that returns tile index, like you said in your command, you can rewrite the get/set pair like this:
public void setTile(int x, int y, Tile tile)
{
tiles[getTileIndex(x, y)] = tile;
}
public Tile getTile(int x, int y)
{
tiles[getTileIndex(x, y)] = tile;
}
public int getTileIndex(int x, int y)
{
return y * width + x;
}
I have class which represents every object in my simple game (player, enemy, beam etc - they all have many commons like speed, position, dmg). So i made class named Thing. Here is how it looks like:
public abstract class Thing {
private Image image;
private float x;
private float y;
private float speed;
private final int WIDTH;
private final int HEIGHT;
public Thing(String filename, float x, float y, float speed) {
try {
Image image = ImageIO.read(new File(filename));
} catch (Exception e) {}
this.x = x;
this.y = y;
this.speed = speed;
WIDTH = image.getWidth(null);
HEIGHT = image.getHeight(null);
}
//Zwraca ksztalt do sprawdzania czy contains...
public Rectangle2D getShade() {
return new Rectangle2D.Float(x, y, WIDTH, HEIGHT);
}
public Image getImage() {
return image;
}
public Point2D getPoint() {
return new Point2D.Float(x, y);
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
I have extended the class Player:
public class Player extends Thing {
public Player(String filename, float x, float y, float speed) {
super(filename, x, y, speed);
}
public void moveToPoint(Point2D targetPoint) {
int targetX = (int)targetPoint.getX();
int targetY = (int)targetPoint.getY();
if ( ((int)x+20 < targetX+3) && ((int)x+20 > targetX-3) ) {
return;
}
float distanceX = targetX - x;
float distanceY = targetY - y;
//Dodanie 20px wymiarow statku
distanceX -= 20;
distanceY -= 20;
//Ustalenie wartosci shiftow
float shiftX = speed;
float shiftY = speed;
if (abs(distanceX) > abs(distanceY)) {
shiftY = abs(distanceY) / abs(distanceX) * speed;
}
if (abs(distanceY) > abs(distanceX)) {
shiftX = abs(distanceX) / abs(distanceY) * speed;
}
//Zmiana kierunku shifta w zaleznosci od polozenia
if (distanceX < 0) {
shiftX = -shiftX;
}
if (distanceY < 0) {
shiftY = -shiftY;
}
//Jezeli statek mialby wyjsc poza granice to przerywamy
if ( (((int)x+shiftX < 0) || ((int)x+shiftX > 260)) || ((y+shiftY < 0) || (y+shiftY > 360)) ) {
return;
}
//Zmiana pozycji gracza
x += shiftX;
y += shiftY;
}
}
And here is the problem because my IDE underlines x, y and speed fields red and tells they cannot be accessed from Player class. I tried to change them into private and default but there appears an error after that. What am I doing wrong? When i create new object from class which extends Thing I want to copy all fields and init them as it is said in constructor. So how to repair it?
You need to use getX(), getY() etc., because x,y, speed are private variables for class Thing.
The fact that Player extends Thing doesn't mean Player can access private fields. Thing provided public get... set... to access its private variables.
Change the variables x, y, and speed to protected, or use the accessors getX(), getY(), getSpeed() (getSpeed() needs to be added in this case) to solve the access issues.
The error that appeared after you changed them to default was the fact that you're calling abs(...) instead of Math.abs(...). Change all instances of abs(...) to Math.abs(...) to get rid of the new errors.