Coloring lines with PGraphic object - java

I have around 1000 points (gps coordinates) which I want to visualize on a map using the Unfolding maps library. The track consists of colored lines (two points). I would like to color the lines based on the speed (if the speed on the track was below 20km/h it should be red otherwise green).
The following code, which represents a custom made line with one color, works:
class MyPolygonMarker extends SimplePolygonMarker {
public void draw(PGraphics pg, List<MapPosition> mapPositions) {
pg.pushStyle();
pg.strokeWeight(2);
pg.fill(255,0,0,0);
pg.stroke(#2688AD);
pg.beginShape();
for(int i=0; i<mapPositions.size();i++)
{
pg.vertex(mapPositions.get(i).x, mapPositions.get(i).y);
}
pg.endShape();
pg.popStyle();
}
}
So in the for loop I would like to put a if statement which checks the speed value. I tried with this:
class MyPolygonMarker extends SimplePolygonMarker {
public void draw(PGraphics pg, List<MapPosition> mapPositions) {
pg.pushStyle();
pg.strokeWeight(2);
pg.fill(255,0,0,0);
for(int i=0; i<mapPositions.size();i++)
{
Float speed_value = Float.parseFloat(lines[i].split("\t")[7]);
if(speed_value > 20)
{
pg.stroke(green);
pg.beginShape();
}
else
{
pg.stroke(red);
pg.beginShape();
}
pg.vertex(mapPositions.get(i).x, mapPositions.get(i).y);
}
pg.endShape();
pg.popStyle();
}
}
This only plots the initial point and nothing else. Could someone tell me what could be wrong?

It might be simply that you need to put the beginShape() before the for loop.
In any case, we are providing an example which seems to do something really close to what you are trying to achieve:
Take a look at ColoredLinesMarker.java for line markers with colors based on the speed. Note, how in that example we are reading the speed from the properties (you don't have to do it like this, but it is good practice).
You can find the full example (including the App and a custom reader for GPX files with speed data) here.

Related

Comparing object references with multiple instantiation

G'day,
I've been trying to finish an assignment and am learning a lot about OO and Java. Nearing the end of this project so very happy but thought I'd try get an interesting question out there, at least for me because of my lack in understanding.
Some background to help clarify, I've used 2D ArrayLists to model a map. I've made a "copy" of the original so that I can update movements and locations, some are permitted some are not.
I use a method to determine which movement is okay and to then update the "copy". There are two classes involved here.
Class GameEngine {
void runGameLoop(ArrayList<ArrayList<String>> map) {
World w = new World();
w.setOriginalMap(map);
while(1) {
w.checkMovement;
}
}
Class World {
ArrayList<ArrayList<String>> originalMap;
void setOriginalMap(ArrayList<ArrayList<String>> map) {
originalMap = new ArrayList<>(map);
}
void checkMovement (String keyEvent, Player obj1) {
ArrayList<ArrayList<String>> copyMap = originalMap;
obj1.setPlayer();
printMap(copyMap, obj1);
}
The issue is that the movement is updated on the map, but the player is now in multiple locations being the ones previous... my map has turned into more of a route. Does this has something with using the same object reference? I make a "copy" inside of the Class method so isn't this local?
Would appreciate some insight.

Java ArrayList update with points seems to replace all elements in said array with the most recent point

short description of what I am trying to do: I'm building a simple game where the user controls a vehicle and after some time more and more ghosts begin following the player, they follow the same trajectory as the player did with a delay.
To accomplish this I create an Array that contains the history of the player's location as a sequence of points. The problem, however, is that when I look at the data stored in this array I see that on all indices only the most recent location is stored.
First I create the array in a botManager class:
public class BotManager {
private ArrayList<Bots> bots;
private List<Point> history;
BotManager() {
history = new ArrayList<>();
bots = new ArrayList<>();
}
Then in the update method of the manager class I add the current location of the player to the array
public void update(Point currLoc) {
history.add(currLoc);
for (Bots bot : bots) {
bot.setLocationData(history);
bot.update();
}
}
A look at the update method in the main GameView class, in case I forgot something here
public void update() {
player.update(playerPoint);
botManager.update(playerPoint);
}
In the bots class' constructor I pass the history list (locationData) and determine its length to find out the delay in positioning. After which the following code handles the position of the bot.
#Override
public void update() {
loc = locationData.get(delay - 1);
this.rectangle = new Rect(loc.x - Constants.BOTSIZE/2, loc.y - Constants.BOTSIZE/2,
loc.x + Constants.BOTSIZE/2, loc.y + Constants.BOTSIZE/2);
}
To get back to the problem, whenever I check the contents of the history array, I find that it only contains one point on all indices, and its the most recent even when I moved the player, causing the ghost to always remain on top of me.
So my question here is, what am I doing wrong here?
Not clear from your posted code, but could it be, that you are just modifying the Point which you are adding instead renewing your object's Point objects?
Try
public void update(Point currLoc) {
history.add(new Point(currLoc)); // new Point object added here
for (Bots bot : bots) {
bot.setLocationData(history);
bot.update();
}
}

I can't get to modify my static variable in java

You give a grid (4x4 here). you need to find out the total no of unique paths from (0,0) to (4,4). main() call a function pathify for this. It finds the possible "next steps" and calls it again. When (4,4) is reached noOfPaths++; is supposed to execute. This doesn't happen and I can't find the problem.
import java.util.ArrayList;
public class NoOfPaths {
static int xRows = 4;
static int yColumns = 4;
static int noOfPaths = 0;
/*A robot is located in the upper-left corner of a 4×4 grid.
* The robot can move either up, down, left, or right,
* but cannot go to the same location twice.
* The robot is trying to reach the lower-right corner of the grid.
* Your task is to find out the number of unique ways to reach the destination.
**/
static ArrayList validNeighbours (int x,int y, ArrayList visited) {
ArrayList valid = new ArrayList();
if((x+1 <= xRows) && !visited.contains(((x+1)*10)+y) ) {
valid.add(((x+1)*10)+y);
}
if((x-1 >= 0) && !visited.contains(((x-1)*10)+y) ) {
valid.add(((x-1)*10)+y);
}
if((y+1 <= yColumns) && !visited.contains(x*10+y+1) ) {
valid.add(x*10+y+1);
}
if((y-1 >= 0) && !visited.contains(x*10+y-1) ) {
valid.add(x*10+y-1);
}
return valid;
}
static void pathify(int x,int y, ArrayList alreadyVisited) {
if(x == xRows && y == yColumns) {
noOfPaths++;
} else {
alreadyVisited.add(x*10+y);
ArrayList callAgain = new ArrayList();
callAgain = validNeighbours(x,y,alreadyVisited);
for (int t=0,temp; t<callAgain.size(); t++) {
temp=(int) callAgain.get(t);
pathify(temp/10, temp%10, alreadyVisited);
}
}
}
public static void main(String[] args) {
ArrayList alreadyVisited = new ArrayList();
pathify(0, 0, alreadyVisited);
System.out.println(noOfPaths);
}
}
The error is in how you're handling alreadyVisited. The first time pathify is called, this list will contain only the initial square (0,0), which is fine. Here's the important part of your code:
for (int t=0,temp; t<callAgain.size(); t++) {
temp=(int) callAgain.get(t);
pathify(temp/10, temp%10, alreadyVisited);
}
You've found the neighbors of the initial cell. Your code will pick the first neighbor; then it will find paths starting with that neighbor, and the recursive calls to pathify will add cells to alreadyVisited.
Now, after all the recursive calls come back, you're ready to find cells starting with the second neighbor of the initial cell. But you have a problem: alreadyVisited still has all the cells it's collected from the paths it found starting with the second neighbor. So you won't find all possible paths starting with the second neighbor; you won't find any path that includes any cell in any path you've previously found. This isn't what you want, since you only want to avoid visiting the same cell in each path--you don't want to avoid visiting the same cell in all your previous paths. (I simplified this a little bit. In reality, the problem will start occurring deeper down the recursive stack, and you won't even find all the paths beginning with the first neighbor.)
When implementing a recursive algorithm, I've found that it's generally a bad idea to keep an intermediate data structure that is shared by recursive invocations that will be modified by those invocations. In this case, that's the list alreadyVisited. The problem is that when an invocation deeper down the stack modifies the structure, this affects invocations further up, because they will see the modifications after the deeper invocations return, which is basically data they need changing underneath them. (I'm not talking about a collection that is used to hold a list of results, if the list is basically write-only.) The way to avoid it here is that instead of adding to alreadyVisited, you could create a clone of this list and then add to it. That way, a deeper invocation can be sure that it's not impacting the shallower invocations by changing their data. That is, instead of
alreadyVisited.add(x*10+y);
write
alreadyVisited = [make a copy of alreadyVisited];
alreadyVisited.add(x*10+y);
The add will modify a new list, not the list that other invocations are using. (Personally, I'd declare a new variable such as newAlreadyVisited, since I don't really like modifying parameters, for readability reasons.)
This may seem inefficient. It will definitely use more memory (although the memory should be garbage-collectible pretty quickly). But trying to share a data structure between recursive invocations is very, very difficult to do correctly. It can be done if you're very careful about cleaning up the changes and restoring the structure to what it was when the method began. That might be necessary if the structure is something like a large tree, making it unfeasible to copy for every invocation. But it can take a lot of skill to make things work.
EDIT: I tested it and it appears to work: 12 if xRows=yColumns=2, 8512 if both are 4 (is that correct?). Another approach: instead of copying the list, I tried
alreadyVisited.remove((Object)(x*10+y));
at the end of the method ((Object) is needed so that Java doesn't think you're removing at an index) and that gave me the same results. If you do that, you'll make sure that alreadyVisited is the same when pathify returns as it was when it started. But I want to emphasize that I don't recommend this "cleanup" approach unless you really know what you're doing.

Finding a way to handle colors and powers on a board game

I am creating a game for my school project, so I am not here for any kind of code, just a global idea on how to do what I am trying to do...
I have Pieces and each piece as is own color and Type like this :
Piece 1 - Yellow - Simple
Piece 2 - Yellow - Explosive
....
Piece 10 - Blue - ChangeColor
At start the game will be field with random pieces from this list (a list created earlier with just one kind of each piece), if we have 3 or more in a row the game as to remove them and count the points, but if one of the 3 (or more) has any "power effect" than the pieces arround must react to that power (hard to explain with my low english level but I think you got it :S..)
For now my game only had simple pieces, and for that I used and enum like this :
public enum CorPeca
{
AMARELO,
AZUL,
VERMELHO;
}
On the board class I was doing this :
this.arrayPecas = new ArrayList<Peca>();
for (CorPeca corPeca : CorPeca.values())
this.arrayPecas.add(new Peca(corPeca));
and on the Pieces class i was doing this
public Peca(CorPeca tipoPeca)
{
this.definirPeca(tipoPeca);
}
public CorPeca getCorPeca() { return this.corPeca; }
public char getCharPeca() { return this.charPeca; }
public void definirPeca(CorPeca tipoPeca)
{
switch (tipoPeca)
{
case AMARELO:
this.charPeca = 'a';
this.corPeca = CorPeca.AMARELO;
break;
case AZUL:
this.charPeca = 'u';
this.corPeca = CorPeca.AZUL;
break;
case VERMELHO:
this.charPeca = 'e';
this.corPeca = CorPeca.VERMELHO;
break;
}
}
But I was thinking of a good method to easily add those "Power Pieces", but more than that, being able to add more colors and more "Powers" in the future...
I was thinking about creating subclasses and using extend, but the whole idea just don't fill in my mind since we can't extends several classes...
So can anyone give me a global idea on how I can archive that ?
The classic OOP way to do this would be to define an abstract base class that represents all pieces and contains common functionality (such as a list of powers):
public abstract class Piece {
// put in fields that every piece has, e.g. x and y co-ordinate here
// array of powers
protected ArrayList<Power> powers=new ArrayList<Power>();
// method to add new powers to the piece
public void addPower(Power power) {
powers.add(power);
}
// power method - optionally overriden by specififc pieces
public void applyPowers() {
for (Power power:powers) {
power.methodToActivatePower();
}
}
// abstract char method
public abstract char getChar();
}
Note that abstract means that you can't directly instantiate this class - you can only make instances of concrete subclasses.
Then extend this class to implement each specific piece:
public class YellowPiece extends Piece {
// override applyPowers for yellow piece (if needed)
#Override
public void applyPowers() {
// code for yellow piece power handling goes here
}
// override char - required
#Override
public char getChar() {
return 'y';
}
}
You can still create an ArrayList<Piece> and populate it with something like:
ArrayList<Piece> pieces = new ArrayList<Piece>();
pieces.add (new YellowPiece());
pieces.add (new GreenPiece());
// etc....
Then if you want to apply the power of a specific piece, just do:
pieces.get(pieceNumber).applyPower();
You'll obviously need to customise this code a lot to make it work in your game, but hopefully it gives you the general idea. Note that there are lots of other ways of achieving the same goals - I've just described the "classic" OOP way.
P.S. Apologies for all code being in English, but your English is far better than my Portugese :-)

Java Greenfoot, cannot link method between files

Working on a project in school, I'm a beginner to programming and I have big problems with the making of Bubble Shooter, I need to get all of the balls of the map before it changes to map2..
Trying to make it with listing all of the balls but the program crashes at the end of the first map and gives us the error-report that it can't load a negative value. I figured it was when it was trying to load the gun and wanted to put an if-statement that says that if "allowedBallTypes != null" or zero, as it might be, than it should load the gun.
cannot find symbol - getAllowedBallTypes();
greenfoot java method class
The bubbleworld class:
public BubbleWorld()
{
super(Map.MAX_WIDTH*Map.COLUMN_WIDTH, Map.MAX_HEIGHT*Map.ROW_HEIGHT, 1,false);
// Max speed. We use time-based animation so this is purely for smoothness,
// because Greenfoot is plain stupid. I can't find a way to get 60 Hz so this is
// what we have to do. Note: Exporting the game seems to cap this to some value < 100. :(
Greenfoot.setSpeed(100);
// Load the map.
map = new Map(this, testMap1);
// Update the allowed ball types. (i.e. we don't want to spawn a
// certain color of balls if the map doesn't contain them!)
map.updateAllowedBallTypes();
// Create the cannon.
Cannon cannon = new Cannon();
addObject(cannon, getWidth()/2, getHeight());
The map class:
public int[] getAllowedBallTypes()
{
return allowedBallTypes;
}
public void updateAllowedBallTypes()
{
int allowedCount = 0;
boolean[] allowed = new boolean[Ball.typeCount];
// Only ball types that exist in the map RIGHT NOW as attached balls will be allowed.
for(Cell c : cells)
{
if(c != null && c.getBall() != null && c.isAttached())
{
int type = c.getBall().getType();
if(!allowed[type])
allowedCount++;
allowed[type] = true;
}
}
allowedBallTypes = new int[allowedCount];
int writeIndex = 0;
for(int type = 0; type < Ball.typeCount; ++type)
{
if(allowed[type])
{
allowedBallTypes[writeIndex++] = type;
}
}
}
The Cannon class:
private void prepareBall()
{
// Get a random ball type from the list of allowed ones. Only balls currently in the map
// will be in the list.
int[] allowedBallTypes = ((BubbleWorld)getWorld()).getMap().getAllowedBallTypes();
int type = allowedBallTypes[Greenfoot.getRandomNumber(allowedBallTypes.length)];
// Create it and add it to the world.
ball = new Ball(type);
getWorld().addObject(ball, getX(), getY());
}
Assuming you are getting that error in the pasted snippet of the Cannon class, the error suggests that there is a problem with the getMap() method of BubbleWorld -- can you paste that in so we can see it? It might not be returning the correct type. In general, you need to paste in more code, including complete classes, and say exactly where the error occurs. An easier way might be to upload your scenario with source code to the greenfoot website (www.greenfoot.org -- use the share function in Greenfoot, and make sure to tick the source code box) and give a link to that.
Based on your code, your map class doesn't seem to have a class-level variable declaration of int[] allowedBallTypes;

Categories