Folks, I'm having a really hard time with rotating a Shape clockwise by 90 degrees. I'm having troubles with completing it. If there is a shape:
.t.
ttt
The method rotateBy90() rotates the above shape by 90 degrees clockwise, so it'll be the following output:
t.
tt
t.
THe shapes are of a String type.
Here what I have and Im pretty sure Im completely doing it wrong. The method can be done by using either char[][], or char[], or String[], or String[][]. Another issue is that rotateBy90() is a void method. COuld smb please help me with this rotation algorithm? Thanks in advance!
import java.util.*;
public class CreateShape {
private int height;
private int width;
private char dc;
private Rotation initialPos;
private Rotation nextPos;
private char[][] shape = new char[height][width];
String[] shapeLayout = new String[height];
String[] rotatedArray;
public CreateShape(int height, int width, char dc)
{
this.height = height;
this.width = width;
this.dc = dc;
initialPos = Rotation.CW0;
}
public void rotateBy90()
{
nextPos = initialPos.next();
String newLayout = "";
int count = 0;
String[] newMatrixColumns= shape.split("\n");
while (count < shape.split("\n")[0].length()) {
for (int i = newMatrixColumns.length - 1; i > -1; i--) {
newLayout += newMatrixColumns[i].charAt(count);
}
newLayout = newLayout + "\n";
count++;
}
}
I don't quite get your approach and where your difficulties lie. I also don't get why you have so many unused fields. You may want to set your width and height fields final, as they shouldn't really change in this case.
Personally I think by far the easiest is to use a char[][]. All you have to do then is iterate your initial char[][] and place the element at the appropriate place in your new char[][]. So in your method you'd have something like
public void rotateBy90()
{
// bla bla
char[][] tempShape = new char[width][height];
for(int j = 0; j < width; j++) {
for(int i = 0; i < height; i++) {
tempShape[...][...] = myShape[i][j]; //I'll leave this as exercise
}
}
myShape = tempShape;
}
Word of caution: be careful with strings. Many string operations involve creating other strings (split, substring, concatenation etc). If you do them in a long loop, you may run out of memory fairly quickly.
Related
My problem that my perlin noise is repeating itself very obviously in very small spaces. Here is an image of what it going on. I know that this does happen after a certain point with all perlin noise, but it seems to be happening almost immediately with mine. I believe that it is caused by my really awful pseudorandom gradient generator, but Im not sure. My code is below.
As a side note, my perlin noise seems to generate very small values, between -.2 and positive .2 and I think this is also caused by my pseudorandom gradient generator.
If anyone has any advice on improving this part of my code, please feel free to tell me. Any ideas would be helpful right now.
Thanks to everyone in advance!
public class Perlin {
int[] p = new int[255];
public Perlin() {
for(int i = 0; i < p.length; i++)
p[i] = i;
shuffle(p);
}
int grads[][] = {
{1,0},{0,1},{-1,0},{0,-1},
{1,1},{-1,1},{1,-1},{-1,-1}
};
public double perlin (double x, double y) {
int unitX = (int)Math.floor(x) & 255; // decide unit square
int unitY = (int)Math.floor(y) & 255; // decide unit square
double relX = x-Math.floor(x); // relative x position
double relY = y-Math.floor(y); // relative y position
// bad pseudorandom gradient -- what i think is causing the problems
int units = unitX+unitY;
int[] gradTL = grads[p[(units)]%(grads.length)];
int[] gradTR = grads[p[(units+1)]%(grads.length)];
int[] gradBL = grads[p[(units+1)]%(grads.length)];
int[] gradBR = grads[p[(units+2)]%(grads.length)];
// distance from edges to point, relative x and y inside the unit square
double[] vecTL = {relX,relY};
double[] vecTR = {relX-1,relY};
double[] vecBL = {relX,relY-1};
double[] vecBR = {relX-1,relY-1};
// dot product
double tl = dot(gradTL,vecTL);
double tr = dot(gradTR,vecTR);
double bl = dot(gradBL,vecBL);
double br = dot(gradBR,vecBR);
// perlins fade curve
double u = fade(relX);
double v = fade(relY);
// lerping the faded values
double x1 = lerp(tl,tr,u);
double y1 = lerp(bl,br,u);
// ditto
return lerp(x1,y1,v);
}
public double dot(int[] grad, double[] dist) {
return (grad[0]*dist[0]) + (grad[1]*dist[1]);
}
public double lerp(double start, double end, double rate){
return start+rate*(end-start);
}
public double fade(double t) {
return t*t*t*(t*(t*6-15)+10);
}
public void shuffle(int[] p) {
Random r = new Random();
for(int i = 0; i < p.length; i++) {
int n = r.nextInt(p.length - i);
// do swap thing
int place = p[i];
p[i] = p[i+n];
p[i+n] = place;
}
}
}
A side note on my gradient generator, I know Ken Perlin used 255 because he was using bits, I just randomly picked it. I dont think it has any effect on the patterns if it is changed.
Your intuition is correct. You calculate:
int units = unitX+unitY;
and then use that as the base of all your gradient table lookups. This guarantees that you get the same values along lines with slope -1, which is exactly what we see assuming (0, 0) is the upper-left corner.
I would suggest using a real hash function to combine your coordinates: xxHash, Murmur3, or even things like CRC32 (which isn't meant to be a hash) would be much better than what you're doing. You could also implement Perlin's original hash function, although it has known issues with anisotropy.
I have this png image:
and a string, say "Hello World". In order to map texture coords for LWJGL, I need to know the X and Y position of each 16x16 character in the PNG. I am completely lost on how one would do that.. Anyone?
Start with something like this:
final int spriteWidth = 16;
final int spriteHeight = 16;
...
int rows = sheet.getWidth()/spriteWidth;
int cols = sheet.getHeight()/spriteHeight;
BufferedImage sheet = ImageIO.read(new File("\\a\b\\c\\sprite_file.png"));
BufferedImage[] images = new BufferedImage[rows * cols];
for(int y = 0; y < cols; y++) {
for(int x = 0; x < rows; x++) {
images[y * x] = sheet.getSubImage(x * rows, y * cols, spriteWidth, spriteHeight);
}
}
Then make final int variables like so:
public static final int SPRITE_0 = 0; public static final int SPRITE_1 = 1;...
and access like so:
images[SPRITE_0]
Edit:
taking into consideration what #MadProgrammer has stated, I would recommend that you split the image into two parts, like so:
(split at the red line)
and then simply altering the code to handle the two different parts. The code will remain the same except for the variables final int spriteWidth and final int spriteHeight. I'm sure you can handle this yourself.
Edit 2:
if you just want the x and y co-ords of the top left corner of each sprite, do the following:
final int spriteWidth = 16;
final int spriteHeight = 16;
...
int rows = sheet.getWidth()/spriteWidth;
int cols = sheet.getHeight()/spriteHeight;
Point[] spriteTopLeftCorner = new Point[rows * cols];
for(int y = 0; y < sheet.getHeight(); y += spriteHeight) {
for(int x = 0; x < sheet.getWidth(); x += spriteWidth) {
spriteTopLeftCorner[y/spriteHeight * x/spriteWidth] = new Point(y, x);
}
}
you would ofcourse still need to make variables representing each sprite's index in this Array, otherwise you wouldn't know what sprite you are taking out.
Do this like so:
public static final int SPRITE_0 = 0; public static final int SPRITE_1 = 1;...
and access like so:
spriteTopLeftCorner[SPRITE_0];
So, as the title reads I am trying to add offsets to my java game. I was given a tip by a friend that I need to minus the offset from where I render the tiles onto my screen.
So I created a random world generator and did the offset thing, but I ran into a problem.
My Code:
public void generateMap(Graphics g) {
block = seed.nextInt(2);
//Render Dirt
if(block == 0) {
g.drawImage(Assets.dirt, x - GameState.xOffset, y - GameState.yOffset, null);
x += 32;
}
//Render Grass
if(block == 1) {
g.drawImage(Assets.grass, x - GameState.xOffset, y - GameState.yOffset, null);
x += 32;
}
//Check Where the X is
if(x > xFinish) {
if(y < yFinish) {
x = xStart;
y += 32;
}
}
}
looks simple enough right? after I do that I create code to add one to the offset every time I loop around:
public void tick() {
xOffset += 1;
}
So after that is done I run it but it does this:
is there any simple way I can fix this so that it appears that the screen "scrolls" to the left?
Is there any simple way I can fix this...
Probably not. Games are complicated. Don't let that dissuade you.
You are generating your game world and drawing in the same methods - you don't want to do this. Separation of responsibility is very important - you don't want a whole bunch of code in one spot doing the same thing. In this case, the functionality to generate the world and the drawing code need to be split.
For the world generation, generate the game world once, and persist it to storage using whatever format you like. Keep this away from the drawing code - it has no place there.
For representing blocks in your world, consider something like this:
class Block {
public BlockType getType() {
return type;
}
public int getxPosition() {
return xPosition;
}
public int getyPosition() {
return yPosition;
}
// hashCode(), equals(), etc omitted, they should be implemented
public static enum BlockType {
Dirt(Assets.dirt),
Grass(Assets.grass);
private final BufferedImage image;
BlockType(BufferedImage image) {
this.image = image;
}
public BufferedImage getImage() {
return image;
}
}
private final BlockType type;
private final int xPosition;
private final int yPosition;
private Block(BlockType type, int xPosition, int yPosition) {
this.type = type;
this.xPosition = xPosition;
this.yPosition = yPosition;
}
public static Block getInstance(BlockType type, int xPosition, int yPosition) {
return new Block(type, xPosition, yPosition);
}
}
You can then use Block.getInstance() to generate a map once, like this:
class GameState {
private final int WORLD_SIZE = 1024;
private Block[][] _world = new Block[WORLD_SIZE][WORLD_SIZE];
private static Random seed = new Random();
public void generateMap() {
int blockTypeLength = Block.BlockType.values().length;
for (int x = 0; x < WORLD_SIZE; x++) {
for (int y = 0; y < WORLD_SIZE; y++) {
int blockType = seed.nextInt(blockTypeLength);
_world[x][y] = Block.getInstance(Block.BlockType.values()[blockType], x, y);
}
}
}
public Block[][] getMap() {
return _world; // not thread safe, shares internal state, all the usual warnings
}
This obviously isn't the only way to generate a world - you would probably generate a world and save, then load from disk in later games (unless it was a short lived game - I don't know, that's your call).
Once you've got the world sorted out, you'd move on to a different module that would handle drawing. Assume GameState has two fields playerX and playerY that represent the player's coordinates in the game world (note: direct fields like this are bad practice, but used to simplify this example):
public void paintComponent(Graphics g) {
super.paintComponent(g);
Block[][] screen = new Block[16][16]; // declare a screen buffer to draw
// Assumes player is in the center of the screen
int screenRadiusX = GameFrame.Assets.SCREENBOUNDS_X / 2 / blockSize;
int screenRadiusY = GameFrame.Assets.SCREENBOUNDS_Y / 2 / blockSize;
for (int x = state.playerX - 8, xS = 0; x < state.playerX + 8; x++, xS++) {
for (int y = state.playerY - 8, yS = 0; y < state.playerY + 8; y++, yS++) {
screen[xS][yS] = world[x][y];
}
}
for (int x = 0; x < screen.length; x++) {
for (int y = 0; y < screen.length; y++) {
Block current = screen[x][y];
g.drawImage(current.getType().getImage(),
x * blockSize, // blockSize is the pixel dimension of
y * blockSize,
null
);
}
}
}
If this helps, then great! I'm glad I was able to help. If not, or if some ideas are still unclear, then I would consider perhaps running through a tutorial or book that walks you through making a game. Don't forget to learn the platform you're coding on during such a process.
I'm making a game in java, is a rpg, however, only with the map the game is slow.
The map is made in TiledMap Editor, therefore, an XML that is read and loaded into an ArrayList. My PC is a dual-core 3.0, 4GB RAM, 1GB Video.
The do the rendering is done as follows:
//method of tileset class
public void loadTileset(){
positions = new int[1 + tilesX * tilesY][2];
int yy = 0;
int xx = 0;
int index = 0;
// save the initial x and y point of each tile in an array named positions
// positions[tileNumber] [0] - X position
// positions[tileNumber] [1] - Y position
for(int i = 1 ; i < positions.length; i++){
if(index == tilesX ){
yy += tileHeight;
xx = 0;
index = 0;
}
positions[i][0] = xx;
positions[i][1] = yy;
xx += tileWidth;
index++;
}
}
//method of map class
public void draw(Graphics2D screen){
//x and y position of each tile on the screen
int x = 0; int y = 0;
for(int j = 0; j < 20 ; j++){
for(int i = initialTile ; i < initialTile + quantTiles ; i++){
int tile = map[j][i];
if(tile != 0){
screen.drawImage(tileSet.getTileImage().getSubimage(tileSet.getTileX(tile), tileSet.getTileY(tile),tileSet.getTileWidth(), tileSet.getTileHeight()),x,y,null);
}
x += tileSet.getTileWidth();
}
x = 0;
y += tileSet.getTileHeight();
}
}
Am I doing something wrong?
Note: I'm new to the forum and to make matters worse I do not understand very much English, so excuse any mistake.
First of all, you should not create the subimages for the tiles during each call. Strictly speaking, you should not call getSubimage at all for images that you want to paint: It will make the image "unmanaged", and this can degrade rendering performance by an order of magnitude. You should only call getSubimage for images that you do not want to render - for example, when you are initially creating individual images for the tiles.
You obviously already have a TileSet class. You could add a bit of functionality to this class so that you can directly access images for the tiles.
Your current code looks like this:
screen.drawImage(
tileSet.getTileImage().getSubimage(
tileSet.getTileX(tile),
tileSet.getTileY(tile),
tileSet.getTileWidth(),
tileSet.getTileHeight()),
x,y,null);
You could change it to look like this:
screen.drawImage(tileSet.getTileImage(tile), x,y,null);
The getTileImage(int tile) method suggested here could then obtain tiles that have been stored internally.
I'll sketch a few lines of code from the tip of my head, you'll probably be able to transfer this into your TileSet class:
class TileSet
{
private Map<Integer, BufferedImage> tileImages;
TileSet()
{
....
prepareTileImages();
}
private void prepareTileImages()
{
tileImages = new HashMap<Integer, BufferedImage>();
for (int tile : allPossibleTileValuesThatMayBeInTheMap)
{
// These are the tiles that you originally rendered
// in your "draw"-Method
BufferedImage image =
getTileImage().getSubimage(
getTileX(tile),
getTileY(tile),
getTileWidth(),
getTileHeight());
// Create a new, managed copy of the image,
// and store it in the map
BufferedImage managedImage = convertToARGB(image);
tileImages.put(tile, managedImage);
}
}
private static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
// This is the new method: For a given "tile" value
// that you found at map[x][y], this returns the
// appropriate tile:
public BufferedImage getTileImage(int tile)
{
return tileImages.get(tile);
}
}
I want to develop a Java-Plugin for ImageJ that flips an image horizontally.
But my code flips only half of the picture. Maybe, there is something wrong with the construction or the output of the image copy?
public class flipHorizontal implements PlugInFilter {
public int setup (String arg, ImagePlus imp)
{
return DOES_ALL;
}
public void run (ImageProcessor ip)
{
int height=ip.getHeight();
int width=ip.getWidth();
ImageProcessor copy = ip;
for (int x=0; x<width; x++) {
for (int y=0; y<height; y++) {
int p=ip.getPixel(width-x-1,y);
copy.putPixel(x,y,p);
}
}
}
}
Your logic is wrong. What you get is normal: you're not processing half of your image but flipping horizontally once half of your image and twice the other half (if I'm not mistaken).
Anyway, if you want to flip horizontally by manipulating pixels yourself directly, as in your code sample, then instead of going to width, you need to go to half the width (width/2).
You then need to actually invert the two pixels from "left" and "right"
Here's an horizontal flip that works:
for (int x = 0; x < w / 2; x++) {
for (int y = 0; y < h; y++) {
final int l = tmp.getRGB( w - (x + 1), y);
final int r = tmp.getRGB( x, y);
tmp.setRGB( x, y, l );
tmp.setRGB( w - (x + 1), y, r );
}
}
There may be "off-by-one" errors in the code above but you should get the idea.
TacticalCoder is correct that you should only be iterating to half way across the image, and you need to save the value from the other side before overwriting it.
There are two additional points that might be worth making, however - one is the the ImageProcessor class already has a method called flipHorizontal, so you can simplify your code to:
public class flipHorizontal implements PlugInFilter {
public int setup (String arg, ImagePlus imp) {
return DOES_ALL;
}
public void run (ImageProcessor ip) {
ip.flipHorizontal();
}
}
The other point that would be worth making is that it seems that you misunderstand what this line means:
ImageProcessor copy = ip;
That's just creating another reference to the same object as ip, so:
copy.putPixel(x,y,p);
... and:
ip.putPixel(x,y,p);
... have exactly the same effect. If you want to create a new ImageProcessor representing the same pixel data, you could do:
ImageProcessor copy = ip.duplicate();
However, that's not necessary in this case.