At first I thought It was easy but when I started doing it I don't know how to continue anymore. My idea was to use panels, then draw thick lines, but then what's the proper way to draw the walls and make my character not move beyond those walls? I just can't imagine how I can possibly do that. Here's a sketch of a maze to illustrate How I will be doing it:
I just started with a Frame and still trying to grasp the idea of doing it.
First, you need a data-structure that represents your maze. Then you can worry about drawing it.
I would suggest a class like this:
class Maze {
public enum Tile { Start, End, Empty, Blocked };
private final Tile[] cells;
private final int width;
private final int height;
public Maze(int width, int height) {
this.width = width;
this.height = height;
this.cells = new Tile[width * height];
Arrays.fill(this.cells, Tile.Empty);
}
public int height() {
return height;
}
public int width() {
return width;
}
public Tile get(int x, int y) {
return cells[index(x, y)];
}
public void set(int x, int y, Tile tile) {
Cells[index(x, y)] = tile;
}
private int index(int x, int y) {
return y * width + x;
}
}
Then I would draw this maze with blocks (squares), rather than lines. A dark block for blocked tiles, and a clear one for empty tiles.
To paint, do something like this.
public void paintTheMaze(graphics g) {
final int tileWidth = 32;
final int tileHeight = 32;
g.setColor(Color.BLACK);
for (int x = 0; x < maze.width(); ++x) {
for (int y = 0; y < maze.height(); ++y) {
if (maze.get(x, y).equals(Tile.Blocked)) (
g.fillRect(x*tileWidth, y*tileHeight, tileWidth, tileHeight);
}
}
)
}
Related
So i am trying to add collision detection for a little game i am creating and i am specifying the width and height of my defender class however i am unable to do so. My code below gives me an error saying the global variable width and height do not exist
class Defender
{
int x,y;
Defender(int x, int y)
{
this.x = x;
this.y = y;
}
void render()
{
//draw a defender
fill(255,0,0);
rect(x,y,50,20);
triangle(x+50,y,x+50,y+20,x+60,y+10);
fill(0,0,100);
rect(x,y-10,20,10);
}
boolean collision()
{
color detectedColour;
for (int i=y; i<y+ Defender.height; i++) {
detectedColour = get(x + Defender.width, i);
if (detectedColour == Alien1) {
return true;
}
}
return false;
}
}
The problem is you're trying to access the variables statically when they do not exist in the class. Create class members that represent the width and height of the defender.
class Defender {
private final int x;
private final int y;
private final int width;
private final int height;
public Defender(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
// getters
}
Defender defender = new Defender(0, 0, 1, 1);
int width = defender.width;
int height = defender.height;
Hey if i have a simple rectangle class, how can i make it so that it creates that rectangle next to each other in a grid like pattern? maybe like 10 rows 10 columns?
public class Vak {
private int posX = 0;
private int posY = 0;
private int width = 50;
private int height = 50;
private Color colour;
public Vak(Color c, int x, int y){
this.colour = c;
this.posX = x;
this.posY = y;
}
public int vakPosY(){
return this.posY;
}
public int vakPosX(){
return this.posX;
}
public void draw (Graphics g){
g.setColor(this.colour);
g.drawRect(posX, posY, width, height);
}
public void move(int numberPixelsX, int numberPixelsY){
this.posX = this.posX + numberPixelsX;
this.posY = this.posY + numberPixelsY;
}
}
this is my code for rectangle "vak"
Is this what you are looking for?
int mapWidth = 10;
int mapHeight = 10;
// tileWidth and tileHeight should probably be public static const fields or static readonly properties of some class, but I put them here for now.
int tileWidth = 50; // Pixels
int tileHeight = 50; // Pixels
// tiles should probably be a field of a Map class (if you have one)
Vak[][] tiles = new Vak[mapWidth][mapHeight];
for(int x = 0; x < mapWidth; x++)
{
for(int y = 0; y < mapHeight; y++)
{
tiles[x][y] = new Vak(Color.white, x*tileWidth, y*tileHeight);
}
}
And then in the drawing part of the main loop:
for(Vak[] row : tiles)
{
for(Vak tile : row)
{
tile.draw(g);
}
}
I am having trouble doing something fairly simple, painting an array of elements. Here is what I have for the paint method in the class with the array: (xB and yB are just the x and y values which I want to increment to make the instances show up in different locations).
public void paint(Graphics pane) {
private Box[] boxes = new Box[NUM_BOX];
for(int i = 0; i<NUM_BOX; i++){
if (xB == 290){
xB = 0;
yB = yB + 20;
}
boxes[i].paint(pane, xB, yB);
xB = xB + 20;
}
And here is what I have in the Box class which is what is being painted:
public class Box {
private final int WIDTH = 20;
private final int HEIGHT = 20;
private boolean up = true;
public void paint(Graphics pane, int x, int y) {
pane.setColor(Color.black);
pane.drawRect(x, y, WIDTH, HEIGHT);
pane.setColor(Color.gray);
pane.fill3DRect(x +2, y+2, WIDTH - 3, HEIGHT - 3, up);
}
}
Every time I run it, it tells me there is a NullPointerException at the boxes[i].paint(pane,xB,yB) line. What am I doing wrong?
Ok so I have been experimenting with java for a few weeks now, following both in class, and online tutorials. I made a simple game where squares fall towards the bottom of the screen, while the player controls a small ball, only moving on the x-axis and trys to avoid them.
The problem that I am having is that the squares start out falling too fast. Right now I have them set as follows:
ix = 0;
iy = 1;
Then in my move() method, I have the following:
hitbox.x += ix;
hitbox.y += iy;
In this example, ix and iy are both integers.
My first assumption was to change the ints to floats, then use:
ix= 0;
iy = 0.5;
and then:
hitbox.x += ix;
hitbox.y += 0.5f;
But this just freezes the objects in their tracks . I believe that this is because cords are taken as integers, so I figured that if I modified my getX() and getY() methods, maybe I could manipulate them somehow to use decimal numbers? But I am not quite sure how to. Any help/hints/solutions to this problem would be Greatly appreciated.
Here is some revelent code, let me know if anymore is needed!
Enemy Manager:
public class EnemyManager {
private int amount;
private List<Enemy> enemies = new ArrayList<Enemy>();
private GameInJavaOne instance;
public EnemyManager(GameInJavaOne instance, int a){
this.amount = a;
this.instance = instance;
spawn();
}
private void spawn(){
Random random = new Random();
int ss = enemies.size();
// If the current amount of enemies is less than the desired amount, we spawn more enemies.
if(ss < amount){
for(int i = 0; i < amount - ss; i++){
enemies.add(new Enemy(instance, random.nextInt(778), random.nextInt(100)+1));
}
// If its greater than the desired number of enemies, remove them.
}else if (ss > 20){
for(int i = 0; i < ss - amount; i++){
enemies.remove(i);
}
}
}
public void draw(Graphics g){
update();
for(Enemy e : enemies) e.draw(g);
}
private void update() {
boolean re = false;
for(int i = 0; i < enemies.size(); i ++){
if(enemies.get(i).isDead()){
enemies.remove(i);
re = true;
}
}
if(re) spawn();
}
public boolean isColliding(Rectangle hitbox){
boolean c =false;
for(int i = 0; i < enemies.size(); i ++){
if(hitbox.intersects(enemies.get(i).getHitbox())) c = true;
}
return c;
}
}
Entity:
public abstract class Entity {
protected int x, y, w, h;
protected boolean removed = false;
public Entity(int x, int y){
this.x = x;
this.y = y;
}
public void Draw(Graphics g){
}
public int getX() { return x; }
public int getY() { return y; }
public int getH() { return h; }
public int getW() { return w; }
}
and the enemy class:
public class Enemy extends Entity{
private Rectangle hitbox;
private int ix, iy;
private boolean dead = false;
private GameInJavaOne instance;
public Enemy(GameInJavaOne instance, int x, int y){
super(x, y);
this.instance = instance;
hitbox = new Rectangle(x, y, 32, 32);
ix = 0;
iy = 1;
}
private void move(){
if(instance.getStage().isCollided(hitbox)){
iy =0;
dead = true;
}
hitbox.x += ix;
hitbox.y += iy;
}
public boolean isDead() {return dead;}
public Rectangle getHitbox() {return hitbox; }
public void draw(Graphics g){
move();
g.setColor(Color.MAGENTA);
g.fillRect(hitbox.x, hitbox.y, hitbox.height, hitbox.width);
}
}
You are using a Rectangle class to represent the position of your box (even though you call it the hitbox), Rectangle does indeed have members x and y which are integers and so when you call
rectangle.x+=0.5f;
What you are really calling is rectangle.x+=(int)0.5f; and (int)0.5f==0.
The Rectangle class is simply inappropriate for holding the position of the box if you want float precision. Consider holding the box's real position as a double or float and casting to int to render it.
So your rendering code would become;
g.fillRect((int)positionX,(int)positionY, hitbox.height, hitbox.width);
where positionX and positionY are doubles. (You could also use Vector2d if you'd prefer to keep x and y together)
Other points
You seem to be extending an Entity class with x,y,w and h and yet never use them, this seems dangerous, why are you extending Entity but recreating your own positional code.
Your game loop isn't shown, however, I can see that you hard code the change in x and y. This is presumably because in your game loop you 'ask for' some frame speed, say 60fps and assume you'll get it. This works fine on a resource rich system, but as soon as you have any resource shortage you will start getting frames that are shorter than 60fps. In most games you don't even notice this because it just makes a larger jump to compensate but here you assume 60fps. It is wise to get an actual frame time and multiply that by a velocity to get you change in x and y.
I am trying to do mouse picking and the tile I click on changes to whatever the opposite tile is ie. grass to dirt, but every grass tile has the same "ID" so every grass tile on the screen changes to dirt. How can I go about generating these tiles in a better way? I want it to be randomly generated and not drawn from an array map of like 000001100.
Block class
public class Block {
public enum BlockType {
Dirt,
Grass,
Selection
}
BlockType Type;
Vector2f Position;
Image texture;
boolean breakable;
public Block(BlockType Type, Vector2f Position, Image texture, boolean breakable) {
this.Type = Type;
this.Position = Position;
this.texture = texture;
this.breakable = breakable;
}
public BlockType getType() {
return Type;
}
public void setType(BlockType value) {
Type = value;
}
public Vector2f getPosition() {
return Position;
}
public void setPosition(Vector2f value) {
Position = value;
}
public Image gettexture() {
return texture;
}
public void settexture(Image value) {
texture = value;
}
public boolean getbreakable() {
return breakable;
}
public void setbreakable(boolean value) {
breakable = value;
}
}
Tile Generation Class
public class TileGen {
Block block;
public Block[] tiles = new Block[2];
public int width, height;
public int[][] index;
boolean selected;
int mouseX, mouseY;
int tileX, tileY;
Image dirt, grass, selection;
SpriteSheet tileSheet;
public void init() throws SlickException {
tileSheet = new SpriteSheet("assets/tiles/tileSheet.png", 64, 64);
grass = tileSheet.getSprite(0,0);
dirt = tileSheet.getSprite(1,0);
selection = tileSheet.getSprite(2,0);
tiles[0] = new Block(BlockType.Grass, new Vector2f(tileX,tileY), grass, true);
tiles[1] = new Block(BlockType.Dirt, new Vector2f(tileX,tileY), dirt, true);
width = 50;
height = 50;
index = new int[width][height];
Random rand = new Random();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
index[x][y] = rand.nextInt(2);
}
}
}
public void update(GameContainer gc) {
Input input = gc.getInput();
mouseX = input.getMouseX();
mouseY = input.getMouseY();
tileX = mouseX / width;
tileY = mouseY / height;
if(input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
selected = true;
}
else{
selected = false;
}
System.out.println(tiles[index[tileX][tileY]]);
}
public void render() {
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
tiles[index[x][y]].texture.draw(x * 64, y *64);
if(IsMouseInsideTile(x, y))
selection.draw(x * 64, y * 64);
if(selected && tiles[index[x][y]].breakable) {
if(tiles[index[tileX][tileY]].Type == BlockType.Grass)
tiles[index[tileX][tileY]].texture = dirt;
}
}
}
}
public boolean IsMouseInsideTile(int x, int y)
{
return (mouseX >= x * 64 && mouseX <= (x + 1) * 64 &&
mouseY >= y * 64 && mouseY <= (y + 1) * 64);
}
I am using slick2d library. I'm not sure if ID is the right word, but I hope you can understand what I am trying to ask.
It looks like your existing structure is fine, but it doesn't look like you understand what it does. The int[][] index array holds a grid of tile types, corresponding to x and y coordinates. To change the tile type at a particular coordinate, all you need to do is set the index array to the type you want.
Specifically, in your render function, you would have something like:
if(IsMouseInsideTile(x, y) && selected && tiles[index[x][y]].breakable)
if(tiles[index[tileX][tileY]].Type == BlockType.Grass)
tiles[index[tileX][tileY]].texture = dirt;
I'd try to figure out exactly what the code you have is doing before modifying it further.
Note: why is this in the render function anyways? You should probably have it in its own function or at least inside your update function.