This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 8 years ago.
I have these classes which is the 3rd and 4th child of a base class in my game:
/*
* List of player states:
* * normal * explode */
public class LocalPlayer extends MovingObjects{
//minus 1 laps to start to accommodate going over the start line for the first time
public int lapsCompleted = -1;
public LocalPlayer(int localPlayerNumber) {
/*
* This line below and the variable localPlayerNumber will not be needed or will be different
* if later on decide to do custom rocket designs - not needed for this stage but bear in mind if the decision is
* made to go down that road this and the game object will have to be reconsidered as early as possible.
*/
super(16, "assets/images/player" + localPlayerNumber , ".jpg", new Vector(373, 450 + (55 * localPlayerNumber)));
}
//basic constructor just initialises MovingObjects Variables to zero values
public LocalPlayer(){
super();
}
///// Uploading Position Methods
public void update(){
if(objectState == "explode"){
}
if(objectState == "normal"){
super.update();
//look for edge of map and stop player leaving and reduce speed to 0
if(position.x > rightEdge - icon.getIconWidth()){
position.x = rightEdge - icon.getIconWidth();
speed = 0;
}else{
if(position.x < leftEdge){
position.x = leftEdge;
speed = 0;
}
}
if(position.y > downEdge - icon.getIconHeight()){
position.y = downEdge - icon.getIconHeight();
speed = 0;
}else{
if(position.y < upEdge){
position.y = upEdge;
speed = 0;
}
}
}
}
///// Movement Methods
//Increases speed
public void up(){
if(speed == 0){
speed = 2;// 2 is minimum speed to achieve all driving angles
}else
if(speed < 11){
speed++;
}
}
//Decreases speed
public void down(){
if(speed > 2){
speed--;
}else{
speed = 0;
}
}
//Turns image and angle 22.5 degrees to the right
public void right(){
if(angle == 337.5)
{
angle = 0;
imageNumber = 0;
}else{
angle = angle + 22.5;
imageNumber = imageNumber + 1;
}
}
//Turns image and angle 22.5 degrees to the left
public void left(){
if(angle == 0)
{
angle = 337.5;
imageNumber = 15;
}else{
angle = angle - 22.5;
imageNumber = imageNumber - 1;
}
}
// works out start grid currently only vertical lines
//add more levels either start all the same way or needs updating
public Vector getStartPos(int serverNumber, CheckPoints line)
{
int row ;
Vector vReturn;
if (serverNumber % 2 == 0) {
// even
row = serverNumber/2;
//this needs some explaining:
//vectorX = row * width of image * gap to next player
//vectorY = getline y and inset slightly(will see how goes)
vReturn = new Vector((line.pos1.x + 10 ) - row * (50 + 10), line.pos1.y + 5);
} else {
// odd
row = (serverNumber + 1)/2;
vReturn = new Vector((line.pos2.x +10) - row * (50 + 10), line.pos2.y - 55);
}
return vReturn;
}
}
and:
import java.awt.image.BufferedImage;
public class NetworkedLocalPlayer extends LocalPlayer{
RocketSpecificServer server = new RocketSpecificServer();
public NetworkedLocalPlayer(String ipAddress,int numOfImages,String filePre, String fileE, CheckPoints finishLine) {
//sign player into server
server.setUpNetwork(ipAddress);
LoadContent.gameSettings = (GameSettings) server.signIn();
//get server number (needed for initialising)
serverNumber = Integer.parseInt(((StringReturnSerial)server.getServerNumber()).s);
//this is temp and should be changed later!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//filePre = filePre + serverNumber;
filePre = filePre + 1;
//Initialise image variables
imageVariables(numOfImages,filePre,fileE);
//work out pos
position = getStartPos(serverNumber,finishLine);
//get images
initImageArray();
}
public void update(){
//updates players info table checks the state of this object
//hasn't been changed by another player
LoadContent.serverPlayerInfo =(PlayerPositionsSerial) server.getPos();
objectState = LoadContent.serverPlayerInfo.playersArray[serverNumber][4];
//usual update
super.update();
//updates server
LoadContent.serverPlayerInfo = (PlayerPositionsSerial) server.updatePos(angle, position.x, position.y,objectState);
}
}
The problem is the update method. In the NetworkedLocalPLayer player class it asks the server for a serialised class which holds all the players positions in the game (and someother bits) that is assigned to the static version in LoadContent class which implements my gameloop. the update method then checks its own position in the playertable array to update its own objectState variable which I can see when using breakpoints comes back as its supposed to as "normal". It then call the parents update method which starts executing and will stop on line in the LocalPlayer class :
if(objectState == "normal"){
the next line is :
super.update();
which should call the super update method of the MovingObjects class which i can also provide if you think it will help but bassically the I have a break opint inside the MovingObjects class and on the super.update() call in the LocalPlayer class which never get hit.
When i change a variable in the game loop to turn multiplayer off which has nothing to do with this but directly used the localPlayer class as it is this method fire perfectly fine and has done unchanged for ages. So is there a reason I cant use super like this? im now getting any errors or exceptions
Thank you
for any help John harris
Never compare Strings with ==. Do it like this (assuming objectState cannot be null - otherwise you could write "explode".equals(objectState) but I find it harder to read):
public void update(){
if(objectState.equals("explode")){
}
if(objectState.equals("normal")){
super.update();
// ...
}
}
If using Java 7, you can also switch on Strings (have a look at the changes introduced with Java 7).
You problem is that objectState == "normal" is always false.
Use "normal".equals(objectState) instead
Related
I am looking for some help with some game code i have inherited from a flight sim. The code below simulates bombs exploding on the ground, it works fine but i am trying to refine it.
At the moment it takes a random value for x and y as a start point and then adds another random value between -20 and 20 to this. It works ok, but doesn't simulate bombs dropping very well as the pattern does not lay along a straight line/
What i would like to achieve though is all x and y points after the first random values, to lay along a straight line, so that the effects called for all appear to lay in a line. It doesn't matter which way the line is orientated.
Thanks for any help
slipper
public static class BombUnit extends CandCGeneric
{
public boolean danger()
{
Point3d point3d = new Point3d();
pos.getAbs(point3d);
Vector3d vector3d = new Vector3d();
Random random = new Random();
Aircraft aircraft = War.GetNearestEnemyAircraft(this, 10000F, 9);
if(counter > 10)
{
counter = 0;
startpoint.set(point3d.x + (double)(random.nextInt(1000) - 500), point3d.y + (double)(random.nextInt(1000) - 500), point3d.z);
}
if(aircraft != null && (aircraft instanceof TypeBomber) && aircraft.getArmy() != myArmy)
{
World.MaxVisualDistance = 50000F;
counter++;
String s = "weapon.bomb_std";
startpoint.x += random.nextInt(40) - 20;
startpoint.y += random.nextInt(40) - 20;
Explosions.generate(this, startpoint, 7F, 0, 30F, !Mission.isNet());
startpoint.z = World.land().HQ(startpoint.x, startpoint.y);
MsgExplosion.send(this, s, startpoint, getOwner(), 0.0F, 7F, 0, 30F);
Engine.land();
int i = Landscape.getPixelMapT(Engine.land().WORLD2PIXX(startpoint.x), Engine.land().WORLD2PIXY(startpoint.y));
if(firecounter < 100 && i >= 16 && i < 20)
{
Eff3DActor.New(null, null, new Loc(startpoint.x, startpoint.y, startpoint.z + 5D, 0.0F, 90F, 0.0F), 1.0F, "Effects/Smokes/CityFire3.eff", 300F);
firecounter++;
}
super.setTimer(15);
}
return true;
}
private static Point3d startpoint = new Point3d();
private int counter;
private int firecounter;
public BombUnit()
{
counter = 11;
firecounter = 0;
Timer1 = Timer2 = 0.05F;
}
}
The code in the question is a mess, but ignoring this and trying to focus on the relevant parts: You can generate a random position for the first point, and a random direction, and then walk along this direction in several steps.
(This still raises the question of whether the direction is really not important. Wouldn't it matter if only the first bomb was dropped in the "valid" area, and the remaining ones outside of the screen?)
However, the relevant code could roughly look like this:
class Bombs
{
private final Random random = new Random(0);
int getScreenSizeX() { ... }
int getScreenSizeY() { ... }
// Method to drop a single bomb at the given position
void dropBombAt(double x, double y) { ... }
void dropBombs(int numberOfBombs, double distanceBetweenBombs)
{
// Create a random position in the screen
double currentX = random.nextDouble() * getScreenSizeX();
double currentY = random.nextDouble() * getScreenSizeY();
// Create a random step size
double directionX = random.nextDouble();
double directionY = random.nextDouble();
double invLength = 1.0 / Math.hypot(directionX, directionY);
double stepX = directionX * invLength * distanceBetweenBombs;
double stepY = directionY * invLength * distanceBetweenBombs;
// Drop the bombs
for (int i=0; i<numberOfBombs; i++)
{
dropBombAt(currentX, currentY);
currentX += stepX;
currentY += stepY;
}
}
}
I am assuming your startpoint is a StartPoint class with x,y,z coordinates as integers in it.
I hope I have understood your problem correctly. It looks like you either want to create a vertical explosion or a horizontal explosion. Since an explosion always occurs on ground, the z coordinate will be zero. Now you can vary one of x or y coordinate to give you a random explosion along a straight line. Whether you choose x or y could be fixed or could be randomized itself. A potential randomized solution below:
public boolean danger() {
// stuff
int orientation = Random.nextInt(2);
if(aircraft != null && (aircraft instanceof TypeBomber) && aircraft.getArmy() != myArmy)
{
// stuff
startPoint = randomizeStartPoint(orientation, startPoint);
// stuff
}
}
StartPoint randomizeStartPoint(int orientation, StartPoint startPoint) {
if(orientation == 0) {
startPoint.x += random.nextInt(40) - 20;
}
else {
startPoint.y += random.nextInt(40) - 20;
}
return startPoint;
}
In response to the image you uploaded, it seems that the orientation of the explosion need not necessarily be horizontal or vertical. So the code I posted above gives a limited solution to your problem.
Since you want any random straight line, your problem boils down to two sub parts:
1. Generate a random straight line equation.
2. Generate random point along this line.
Now, a straight line equation in coordinate geometry is y = mx + c where m is the slope and c is the constant where the line crosses the y-axis. The problem with c is that it gives rise to irrational coordinates. I am assuming you are looking for integer coordinates only, since this will ensure that your points are accurately plotted. (You could do with rational fractions, but then a fraction like 1/3 will still result in loss of accuracy). The best way to get rid of this irrational problem is to get rid of c. So now your straight line always looks like y = mx. So for step one, you have to generate a random m.
Then for step 2, you can either generate a random x or random y. It doesn't matter which one, since either one will result in random coordinates.
Here is a possible code for the solution:
int generateRandomSlope() {
return Random.nextInt(100); // arbitrarily chose 100.
}
int randomizeStartPoint(int m, StartPoint startPoint) { // takes the slope we generated earlier. without the slope, your points will never be on a straight line!
startPoint.x += random.nextInt(40) - 20;
startPoint.y += x * m; // because a line equation is y = mx
return startPoint;
}
public boolean danger() {
// stuff
int m = generateRandomSlope(); // you may want to generate this elsewhere so that it doesn't change each time danger() is called.
if(aircraft != null && (aircraft instanceof TypeBomber) && aircraft.getArmy() != myArmy)
{
// stuff
startPoint = randomizeStartPoint(m, startPoint);
// stuff
}
}
Again, this is not a complete or the best solution.
I have been working on android apps for a long time but now I have decided to create a game aside with my pre-calculus final. I have completed the whole code and it works perfectly except one tiny issue. First of the game is based on flying pig(my classmate's face) avoiding top and bottom osticle. I developed an algorithm so that the obsticles are evenly spaced and based on random selection placed either as the top or bottom of the screen but never both at the same time!. The algorithm that needs improvement is in the 3rd code segment!
This is the screenshot of the problem: screenshot here
(My account is new so stackoverflow wont let me to share photos directly)
This is the class that calls updates for all dynamic objects (ship = pig, bacon = bonus item, BM = BarrierManager class's update() which updates the obsticles)
//this will update the resources
void Update(float dt) {
ship.update(dt);
//bumbing
if (!ship.death) {
background.update(dt);
**BM.update(dt);**
for (int i = 0; i % 5 == 0; i++) {
bacon.update(dt, BM.position);
}
}
ArrayList<Point> bacon_point = new ArrayList<Point>(bacon.getArray());
if (ship.bump(bacon_point.get(0), bacon_point.get(1), bacon_point.get(2), bacon_point.get(3))) {
bacon.setX(-200);
bacon.setY(-200);
Message msg = BM.game_panel.game.handler.obtainMessage();
msg.what = 0;
BM.game_panel.game.handler.sendMessage(msg);
}
for (int i = 0; i < BM.TopWalls.size(); i++) {
ArrayList<Point> temp = new ArrayList<Point>(BM.TopWalls.get(i).getArray());
//after we have accest the TopWalls arraylist we can call bump that check TopWalls object's points position with the pig's points
ArrayList<Point> temp2 = new ArrayList<Point>(BM.BottomWalls.get(i).getArray());
//after we have accest the TopWalls arraylist we can call bump that check BottomWalls object's points position with the pig's points
if ((ship.bump(temp.get(0), temp.get(1), temp.get(2), temp.get(3))) || (ship.bump(temp2.get(0), temp2.get(1), temp2.get(2), temp2.get(3))) || ship.death) {
ship.death = true;
game.onStop();
while(f==0) {
MediaPlayer mp = MediaPlayer.create(game, R.raw.explosion_fart);
mp.start();
f++;
}
f++;
Message msg = BM.game_panel.game.handler.obtainMessage();
msg.what = 1;
BM.game_panel.game.handler.sendMessage(msg);
i = BM.TopWalls.size()-1;
if(f == 8){
thread.setRunning(false);
}
}
}
}
In the BarrierManager I have created this update method which takes float dt = MainTheards general time for the game.
TopWalls is ArrayList this ArrayList is composed of top obsticles. Bottom walls is the same but BottomWalls.
//zreb decides if it should create TopWalls or BottomWalls object. This parameter is later transfered to the Barier.update method where I work with it
public void update(float dt){
for (int i=0;i<Num+1; i++) {
int zreb = new Random().nextInt(2);
//{if} to make the spacing bigger
if (i % 5 == 0){
**TopWalls.get(i).update(dt, true, zreb);
BottomWalls.get(i).update(dt, false, zreb);**
if(zreb == 0){
position.set(TopWalls.get(i).getX(), TopWalls.get(i).getY());
}
else{
position.set(BottomWalls.get(i).getX(),BottomWalls.get(i).getY());
}
}
}
}
Now this algoritm in the Barrier.class is where the magic went wrong. This update method takes the float dt mentioned earlier, a boolean variable for determining if the obsticle we work with at that instance is the Top or Bottom, and the zreb random int that determines if the top or bottom obsticle is going to be shown.
//problem! needs to be discussed
public void update(float dt, boolean b, int zreb) {
//checking if the barrier is still there
if (x<-bitmap.getWidth()){
//'b'is passed from the Barriermanager - 'update' method, determining if we have to use monkey-true or farmer-false
int raz = 200;
int vyska = BM.dpos;
//'zreb' helps me to randomly determine if monkey or ballard is going to appear
//here it determines if we are going to have Top or Bottom obsticle in the game
if(zreb == 1) {
vyska = BM.dpos - raz;
}
else {
vyska = BM.dpos + raz;
}
//koniec tohto trienedia
if (b)
{
//setting the y value for the top wall
y = vyska - BM.dl/2 - bitmap.getHeight()/2;
}
else{
//setting the y value for bottom wall
y = vyska + BM.dl/2 + bitmap.getHeight()/2;
}
//setting x-value
x = (int) (x +bitmap.getWidth()*(BM.TopWalls.size()-1));
}
x = (int) (x - BM.game_panel.ShipSpeed*dt);
}
Do you have any idea why this "one-or-the-other" condition is not working properly?
This would help me lot because this error made me deactivate the app from the store.
I'm making a game engine, and I want to have a rope object in the game. I've created the rope, and it behaves perfectly, except that if I apply a force to the bottom of the rope (like attaching the player to the rope and moving the player), the force doesn't propagate to the rest of the rope.
This is what the rope looks like, even when I try to move the player:
I would like the rope to move along with the player, but keep the player attached to the bottom of the rope.
This is the update method from the Rope class
public void update() {
for (int i = 0; i < segments.size(); i++) {
RopeSegment previous = null;
if (i != 0) {
previous = segments.get(i - 1);
}
final RopeSegment seg = segments.get(i);
// do collision detection
seg.update();
// if we are not the first (position locked) segment
if (previous != null) {
// if we are out of range of the previous segment
if (seg.getCenter().toPoint().distanceSq(previous.getCenter().toPoint()) > MAX_DIST * MAX_DIST) {
// pull us back in
final Vec2D previousCenter = previous.getPosition();
seg.applyForce(previousCenter.subtract(seg.getPosition()).multiply(0.01));
seg.setPosition(previousCenter.add(seg.getPosition().subtract(previousCenter).unit()
.multiply(MAX_DIST)));
}
}
}
// lock position of first segment
segments.get(0).setPosition(getLockposition());
segments.get(0).setVelocity(new Vec2D(0, 0));
}
and this is the relevant code from the update method of the Player class
if (rope != null) {
if (rope.getLockposition().toPoint().distanceSq(getCenter().toPoint()) > Rope.MAX_DIST * Rope.MAX_DIST) {
setCenter(rope.getLastSegment().getCenter());
}
}
If I were you: I would find the number of rope segments (Depending on height), there are between the player and the top of the screen (Y : 0px); thereby, allowing you to constantly update an integer; or appropriate size variable, with how many segments to draw. Then, every time you redraw, you can make the rope above the player. This would entitle deleting most of what you have, but I believe it to be a bit more efficient. If you want to make the rope look more 'Rope Like', then you could use an ArrayList, updated every time you go to draw, which will have a class defining position and a Vec2D which holds velocity, which will be used to increase the x position of the rope. e.g.
List<Rope> ropes = new ArrayList<>(); //Fill This With Ropes. . . //First is The Farthest Up!
class Rope {
int x, y;
short velocity;
//Constructor
}
void updateRopes(int playerX) {
for(Rope r : ropes)
r.x += (r.velocity < (playerX - r.x)) ? r.velocity : (playerX - r.x); //You Can Make a Variable Which Holds (playerX - r.x) For Efficiency, or Keep For RAM
}
void playerMove() {
int yDec = ropes.size() / 5; //5 Is the Presumable Speed of The Character. . .
int tempVeloc = 5;
for(int i = 0; i < ropes.size(); i++)
if((i % yDec) == 0 & i != 0) tempVeloc -= 1;
//The Other Player-Move Based Code. . .
}
EDIT:
I believe your problem is that you are not actually editing the classes inside of the array, you are making a constant copy of them; thereby not changing the object because you have not made a pointer to them. . .
What you should do is this:
RopeSegment seg = segments.get(i - 1);
I just started a new 2D game using Java, LWJGL, and Slick Util but I can't seem to figure out a good way to make collision detection.
If I wanted to, it would be easy to detect collision between 2 entities with the Rectangle intersect method, but it can only check the collision with a certain area you specify.
I have thought that I could make a list of every entity and its coordinates as its created and then run the intersect method through the list, but then it would check for collision with every entity on the entire map for every time the game updated and I think that would be too inefficient.
Does anyone know a more efficient way to create collision detection? If there was some way i could check if there was an entity at every point the character moved that would probably be the best.
If I have not enough information or I made this sound too confusing please tell me and I can try to clarify things. Also as a side question, what are the benefits of using slick util or slick 2D over one another. Thanks for the help!
The usual way to solve this is a scene graph, a hierarchical system of the objects of the game world.
You might want to look at this and this.
Shortened: you logically group your objects under nodes and assign the nodes a bounding rectangle that encompasses all its sub-nodes and leaves(objects). Everything is grouped again under one main node to access the tree. Now you can test a object for collision with a node, usually starting from the main node. If you get a hit you check its sub-nodes and leaves.
This will take some time to implement but can cut down on CPU usage if the tree structure/grouping is done right. It has also the benefit that you can implement local transforms which makes moving objects relative to each other easier.
Because I hate "The usual way", I made an array of all the coordinates and then checked if a single point hit the coordinate.
Here is a slight modification of my code to demonstrate (It is in 3D):
for (CannonBall can : GameServer.ballss){ //Go through all cannonballs
if (can.owner != cl){ //Can.owner is the ship, cl is the player the cannonball is being checked with to see if colliding.
int distancex = (int) (can.x - cl.z);
int distancez = (int) (can.z - cl.x);
final int distancey = (int) (can.y - cl.y);
double xRot = Math.cos(Math.toRadians(cl.rotation)) * (distancex - 0) - Math.sin(Math.toRadians(cl.rotation)) * (distancez - 0) + 0;
double zRot = Math.sin(Math.toRadians(cl.rotation)) * (distancex - 0) - Math.cos(Math.toRadians(cl.rotation)) * (distancez - 0) + 0;
distancex = (int) xRot;
distancez = (int) zRot;
try{
if (true){ //Skip different coordinates for different ships for demonstration purposes
i = GameServer.coords[GameServer.DELTA + distancex][GameServer.DELTA + distancez][GameServer.DELTA + (distancey)];
}
if (i == 1){
if (can.owner != cl){
remcan.add(can);
if (can.type == 0){
double damage = (100 + Math.random()*25);
if (cl.type == 1){
damage/=2;
}
if (cl.type == 2){
damage*=2;
}
cl.damage-=damage;
}
if (can.type == 1){
double damage = (Math.random() * 500);
if (cl.type == 1){
damage/=2;
}
if (cl.type == 2){
damage*=2;
}
cl.damage-=damage;
}else{
double damage = (100 + Math.random()*25);
if (cl.type == 1){
damage/=2;
}
if (cl.type == 2){
damage*=2;
}
cl.damage-=damage;
}
crash = true;
if (cl.damage < 1){
if (!cl.sinking){
cl.sinking = true;
}
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
GameServer.coords is an int[][][], which is given coordinates like so:
public static int[][][] coords;
public void CollisionSetup(){
try{
File f = new File("res/coords.txt");
String coords = readTextFile(f.getAbsolutePath());
for (int i = 0; i < coords.length();){
int i1 = i;
for (; i1 < coords.length(); i1++){
if (String.valueOf(coords.charAt(i1)).contains(",")){
break;
}
}
String x = coords.substring(i, i1).replace(",", "");
i = i1;
i1 = i + 1;
for (; i1 < coords.length(); i1++){
if (String.valueOf(coords.charAt(i1)).contains(",")){
break;
}
}
String y = coords.substring(i, i1).replace(",", "");;
i = i1;
i1 = i + 1;
for (; i1 < coords.length(); i1++){
if (String.valueOf(coords.charAt(i1)).contains(",")){
break;
}
}
String z = coords.substring(i, i1).replace(",", "");;
i = i1 + 1;
//buildx.append(String.valueOf(coords.charAt(i)));
////System.out.println(x);
////System.out.println(y);
////System.out.println(z);
//x = String.valueOf((int)Double.parseDouble(x));
//y = String.valueOf((int)Double.parseDouble(y));
//z = String.valueOf((int)Double.parseDouble(z));
double sx = Double.valueOf(x);
double sy = Double.valueOf(y);
double sz = Double.valueOf(z);
javax.vecmath.Vector3f cor = new javax.vecmath.Vector3f(Float.parseFloat(x), Float.parseFloat(y), Float.parseFloat(z));
//if (!arr.contains(cor)){
if (cor.y > 0)
arr.add(new javax.vecmath.Vector3f(cor));
if (!ship.contains(new Vector3f((int) sx, (int) sy, (int) sz)))
ship.add(new Vector3f((int) sx, (int) sy, (int) sz));
Float.parseFloat(z)));
}
}
public void setUpPhysics() {
//coords = new int[20][20];
coords = new int[80][80][80];
coords1 = new int[80][80];
//coords[-5 + DELTA][7 + DELTA] = 11;
for (javax.vecmath.Vector3f vec : arr){
coords[DELTA+(int) vec.x][DELTA+(int) vec.z][DELTA + (int) vec.y] = 1; //This is line 124
coords1[DELTA+(int) vec.x][DELTA+(int) vec.z] = 1;
}
}
Though it has limitations on collision interaction, it works for cannonballs colliding with a ship and checking the front of a ship to see if it has hit another ship. Also, it uses barely any CPU.
No idea on the opinions of other programmers on such a method.
I am developing a snake and ladder game in java, that is configurable-that is, you can set the 'head' and 'tail' positions for snakes and ladders in it.I have tried loading snake images and re-sizing them appropriately for fitting in the bounds of the head and tail positions, but that seems to affect the quality of the images.
Can anyone suggest a better method/algorithm?
Help greatly appreciated.
I would suggest splitting the snake graphics into sections - a head, a tail and one or more middle body sections. Then, depending on the required length of snake you can construct it from drawing the middle section as long as required.
The approach you are using has two "problems" which may cause poor quality:
You are (I assume) upscaling graphic images, which will cause blockiness.
If you change the scale of both x and y axis (eg zoom in) long snakes will be fatter and wider than short snakes, which isn't what people expect to see.
I would modify fd's solution somewhat. Proceed as follows:
Prepare a graphic for the head, the tail, and a single section of middle so you can chain any number of middle sections together.
When you need to draw a snake, calculate its length. Then see how many middle sections you need for the whole snake to be equal to or greater than this calculated length.
Create a bitmap buffer of the correct size to hold a horizontal (or vertical!) snake with the correct number of middle sections. Draw the background as transparent, then draw the snake into this bitmap. It will typically be slightly longer than you need.
Scale and rotate the bitmap and place it at the correct location on your board.
You will still be scaling to some extent, but the scale factor should be small enough to not be obvious. For example, if you need 5.5 middle sections to make an exact fit, then you would draw 6 middle sections and then scale the whole snake by about 5.5/6 to make it exactly the right length. This is less than 10% change, so shouldn't be obvious.
This solves the problems above:
The width of the snake will only vary slightly
You only downscale, never upscale.
It has the following practical benefits:
You only have to lay out the snake horizontally (or vertically), which is easy to do
It should be very efficient. All the real work is done by the graphics library which has to rotate, zoom and place the constructed snake. On most platforms these operations are implemented as a transformation matrix which is calculated in hardware and hence very fast. I use this approach extensively in an Android app I wrote, and it is extremely fast.
Note that the more "wiggles" in the snake, the less your scaling factor will differ from 1.0 and hence the less variation in width.
public class SankesAndLadder {
static int turn = 0;
static int[] gameBoard = new int[100];
static Map<Integer, Integer> ladderPositionValue;
static Map<Integer, Integer> snakePositionValue;
static int userPosition = 0;
static int computerPosition = 0;
public static void populateBoard() {
ladderPositionValue = new HashMap<>();
snakePositionValue = new HashMap<>();
// SUPPOSE WE HAVE 10 LADDERS AND 10 SNAKES
for (int i = 0; i < 10; i++) {
int ladderPositionKey = (int) (Math.random() * 85) + 10;
if (!ladderPositionValue.keySet().contains(ladderPositionKey)) {
ladderPositionValue.put((int) (Math.random() * 100) + 1, (int) (Math.random() * 10) + 5);
} else {
i--;
}
int snakePositionKey = (int) (Math.random() * 95) + 15;
if (!ladderPositionValue.keySet().contains(ladderPositionKey) &&
!snakePositionValue.keySet().contains(ladderPositionKey)) {
snakePositionValue.put((int) (Math.random() * 100) + 1, (int) (Math.random() * 10) + 5);
} else {
i--;
}
}
}
public static int rollDice(int repeat) {
System.out.println("ROLLING DICE...PRESS ANY KEY TO CONTINUE:");
Scanner in = new Scanner(System.in);
String cont = in.nextLine();
int rolledNo = (int) (Math.random() * 6) + 1;
if (rolledNo == 6) {
System.out.println("NUMBER IS:" + rolledNo + ". ANOTHER CHANCE.");
rollDice(repeat++);
} else {
System.out.println("NUMBER IS:" + rolledNo);
}
int finalCount = rolledNo + (repeat * 6);
return finalCount;
}
public static boolean userTurn() {
if (turn % 2 == 0) {
turn++;
return true;
}
turn++;
return false;
}
public static void newUserPosition(int rolledNo) {
userPosition = userPosition + rolledNo;
System.out.println("YOUR NEW POSITION IS:" + userPosition);
userPosition = checkSnakeOrLadder(userPosition);
}
public static void newComputerPosition(int rolledNo) {
computerPosition = computerPosition + rolledNo;
computerPosition = checkSnakeOrLadder(userPosition);
}
private static int checkSnakeOrLadder(int position) {
if (snakePositionValue.keySet().contains(position)) {
System.out.println("AAAAAAAAAAAHHHH ... BITTEN BY SNAKE");
position = position - snakePositionValue.get(position);
} else if (ladderPositionValue.keySet().contains(position)) {
System.out.println("YAAAAAAAY.. GOT A LADDER");
position = position + ladderPositionValue.get(position);
}
return position;
}
public static void main(String args[]) {
System.out.println("WELCOME TO SNAKES & LADDER");
System.out.println("***************************");
populateBoard();
while (userPosition != 100 && computerPosition != 100) {
if (userTurn()) {
System.out.println("YOUR TURN:");
int rolledNo = rollDice(0);
System.out.println("MOVING YOUR POSITION:");
newUserPosition(rolledNo);
} else {
System.out.println("COMPUTER TURN:");
int rolledNo = rollDice(0);
System.out.println("MOVING COMPUTER POSITION:");
newComputerPosition(rolledNo);
}
}
if (userPosition == 100) {
System.out.println("YOUR ARE THE WINNER!!!!");
} else if (computerPosition == 100) {
System.out.println("COMPUTER WON!!!!");
}
}
}