FRC Java Mecanum Drive - java

I am the programmer for my FRC Team 4468 and we are using mecanum wheels this year. We are trying to control the robot with two joysticks, one for moving in a direction (mecStick), and another for rotation (rotStick) using this line of code.
myDrive.mecanumDrive_Cartesian(mecStick.getX(), mecStick.getX(), rotStick.getY(), 0);
The robot will move in the Y direction (fowards, backwards), and will rotate but won't move in the X axis. Could someone tell me what i'm doing wrong please.
Thanks :-)
public class RobotTemplate extends SimpleRobot {
RobotDrive myDrive = new RobotDrive(1,2,3,4);
Joystick mecStick = new Joystick(1);
Joystick rotStick = new Joystick(2);
public void robotInit() {
}
public void autonomous() {
}
public void operatorControl() {
//myDrive.setSafetyEnabled(true);
myDrive.mecanumDrive_Cartesian(mecStick.getX(), mecStick.getX(), rotStick.getY(), 0);
Timer.delay(0.01);
}
}

Looks like you pass mecStick.getX() twice, one should probably be mecStick.getY(). I'm not familiar with the RobotDrive class, so I'm not sure which should be switched. The WPILib Javadoc is your friend, you can find a copy hosted by team 2168 at http://team2168.org/javadoc/. Look for RobotDrive on the left bottom list, and check there.
Best of luck from 1902, Exploding Bacon!

Related

How to properly "layer" images (and changing the source) without inheriting from Swing

I'm finishing my homework in OOP Java. The assignment is to load images on a JFrame, be able to move them around (top layer should be prioritized, it is currently not) and click them to "flip them" (change the source of the image essentially). I'm currently having trouble finding a solution on how to properly "layer" images that are visible on the screen and to prioritize the images on the top first (currently the bottom ones are being prioritized).
I also have issues finding a good way to change the source of the images, as our teacher has prohibited extending the Picture class with Swing.
My first attempt at solving this was saving the information of every individual "Picture" object in an ArrayList. This works to save the position of the images but does not solve my issue with the layering. I also wanted to use JLayeredPane but as I found out, it was harder than I thought as I have yet to find a viable solution this way (I might be missing some obvious facts about how it works).
I'm thinking what probably needs to happen is that I save the "position" of each image in some type of Array, then using this array to print out the images via paintComponent # ImagePanel. This is currently what I am doing but it does not act as I wish it to. I think my way of loading in the images in the "Picture" class might have something to do with it. I don't have a lot of experience in Java so all of this is new to me.
I don't want to print out all of my codes as I have 4 classes, so I'm going to print out what I feel are the essential methods in each class. If there's something missing that you guys need in order to guide me in the right direction I'll provide that aswell.
draw # Picture
public void draw(Graphics g, int i) {
try {
BufferedImage img = ImageIO.read(new File("images/icon_"+ i +".gif"));
g.drawImage(img, x, y, null);
} catch(IOException ie) {
System.out.println("Could not find images");
}
}
mousePressed & mouseDragged # MouseHandler
public void mousePressed (MouseEvent e) {
Point point = e.getPoint();
chosen = imagepanel.locateImage(point);
}
public void mouseDragged (MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (chosen != null) {
imagepanel.moveImage(chosen, x, y);
}
}
loadImages & paintComponent # ImagePanel
private final static int IMAGES = 7;
private ArrayList <Picture> imageCollection = new ArrayList<>();
private Picture im;
Random rand = new Random();
public void loadImages() {
for(int i=0; i<IMAGES; i++) {
int x = rand.nextInt(400) + 40;
int y = rand.nextInt(400) + 60;
im = new Picture(x,y);
imageCollection.add(im);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int i = 0;
for (Picture im : imageCollection) {
i++;
im.draw(g, i);
}
}
I expect the images to stack on top of eachother whenever "flipped" (clicked) or moved (dragged). They do not currently do this as they just maintain their "depth" position. I've tried implementing an Image[] without success.
I also have a flip method where I tried using setIcon (I was using ImageIcon instead of Image previously) but this did not really work for some reason.
I also would love for any feedback on the code so far and any improvements that could be made as I always want to improve.
EDIT: I manage to solve my problems, however I'm sure there's a better way to do this.
public void placeFirst(Picture im) {
int pos = imageCollection.indexOf(im);
imageCollection.remove(pos);
imageCollection.add(0, im);
}
public void flipImage(Picture im) {
im.flip();
placeFirst(im);
repaint();
}
public void moveImage(Picture im, Point point) {
im.move(point.x-(im.getWidth(im)/2), point.y-(im.getHeight(im)/2));
placeFirst(im);
repaint();
}
public Picture locateImage(Point point) {
for (int i=0; i<imageCollection.size(); i++) {
Picture im = imageCollection.get(i);
if (im.fits(point)) {
return im;
}
}
return null;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// There probably exists a better and visually nicer way of doing this
for (int i=imageCollection.size()-1; i>=0; i--) {
Picture im = imageCollection.get(i);
im.draw(g);
}
}
chosen = imagepanel.locateImage(point);
Well, we don't know how the locateImage(...) method works, but I would guess you just iterate through the array until you find a match.
So you will always find the same match.
So if you want an image to stack on top you have two issues:
you need to modify the search order so that when you click on an image you move it to position 0 in the ArrayList so it is always found first
but know when you paint images you need to paint images from the end of the ArrayList to the beginning, so the first image in the ArrayList gets painted last.

Drawing Text Letter By Letter in Intervals (LIBGDX)

I'm using LibGDX and I want to know if it is possible to do a speech system where the text gets drawn letter by letter, or slowly, like a person speaking, instead of just appearing. Is this possible? Do I need to make a function to do it or does LibGDX or java have it built in??
Thanks,
Luke
I would recommend something similar to Sameera's comment, although a wait generally isn't a good idea for a game as it stops everything else, unless you do it in a separate thread.
Instead of waiting, perhaps use your delta times:
private float timeSinceLastLetter = 0f;
private static final float TIME_PER_LETTER = 100f;
public void render(float deltaTime) {
// do your other rendering
if(timeSinceLastLetter > TIME_PER_LETTER) {
timeSinceLastLetter = 0f;
// render your next letter here
} else {
timeSinceLastLetter += deltaTime;
}
}
There's plenty more details that need filling in, but that should give a rough idea

LibGDX — How to detect if 3d object was clicked on?

I'm trying to make a simple bit of code that will detect whether a model was clicked on. So far the best method I've seen is to create some sort of rectangle around the mesh and detect with Gdx.input.justTouched() to get the x,y coordinates, and then check if the rectangle contains the coordinates returned by justTouched().
I have no idea if there's a better way to do this, some kind of mesh onClick listener or something that LibGDX has in place that I'm unaware of (I've been scouring Google and the javadocs but I can't seem to find anything). I don't really need to deal with the z-axis coordinate, at least I don't think so. I only have the one PerspectiveCamera and it's not going to be moving around that much (not sure if this matters?)
Anyways, in my render() method I have:
if (Gdx.input.justTouched()) {
//this returns the correct values relative to the screen size
Vector2 pos = new Vector2(Gdx.input.getX(), Gdx.input.getY());
//I'm not sure how to get the correct rectangle to see what the
//width and height are for the model relative to the screen?
Rectangle modelBounds = new Rectangle(<<not sure what to put here>>);
if (modelBounds.contains(pos.x, pos.y) {
System.out.println("Model is being touched at: " + pos.x + ", " + pos.y);
}
}
I'm really not sure if this is the correct way to do this. I can get the position of the model with:
modelInstance.getNode("Node1").globalTransform.getTranslation(new Vector3());
but I'm not sure how to get the width and height as a rectangle relative to the screen size, if it's even possible.
I'm also unsure if this would cause massive lag, as I'm going to have about 7 nodes total that I need to detect if they're clicked on or not.
Is there a better way to do this? If not, is there a way to get the model width & height relative to the screensize (or camera, maybe)?
EDIT: Read about using Bounding Boxes, seems like what I need. Not quite sure how to implement it properly, however. I've changed my code to such:
public ModelInstance modelInstance;
public BoundingBox modelBounds;
#Override
public void create() {
...
//omitted irrelevant bits of code
modelInstance = new ModelInstance(heatExchangerModel);
modelBounds = modelInstance.calculateBoundingBox(new BoundingBox());
}
#Override
public void render() {
...
if (Gdx.input.justTouched()) {
Vector3 pos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
System.out.println(pos);
if (modelBounds.contains(pos)) {
System.out.println("Touching the model");
}
}
}
I'm not really sure what the output of BoundingBox is supposed to be, or how the numbers it gives me correlates to the position in a 2d space. Hmm..
EDIT2: Think I'm getting closer.. Read about Rays and the .getPickRay method for my PerspectiveCamera. .getPickRay seems to return completely unusable numbers though, like really tiny numbers. I think I need to do something like:
if (Gdx.input.justTouched()) {
Vector3 intersection = new Vector3();
Ray pickRay = perspectiveCamera.getPickRay(Gdx.input.getX(), Gdx.input.getY());
Intersector.intersectRayBounds(pickRay, modelBounds, intersection);
}
and then intersection should give me the point where they overlap. It appears to be not working, however, giving me really small numbers like (4.8066642E-5, 2.9180354E-5, 1.0) .. hmmm..

Android Missile sprite

I am trying to make a onTouchEvent to create a missile that will launch from my character sprite and forward.
I have this working using
if (missdraw = true){
canvas.drawBitmap(missile,missilex,missileY,null);
missilex = missilex + 14;
missdraw = false;
}
in my onDraw method, but the problem is it will only create one at a time.
I tried to create a class to deal with this, but this just causes an error and crashes when i try to fire.
here is what i use for the class: (this is in the ondraw in my gameview)
for (Batcher missile : missiles ){
missile.onDraw(canvas);
}
this is in the class
public Batcher(List<Batcher> temps, ScreenActivity newView, float x,
float y, Bitmap missile){
this.x = 1;
this.y = 2;
this.missile = missile;
}
public void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
canvas.drawBitmap(missile, x,y, null);
}
I would appreciate any help, but also if you could explain how it would work, instead of just code, as im quite new to programming, and really need to understand what im doing and why im doing it, rather than just copying peoples code because it works.
Cheers Phil.
Your concepts are pretty good, actually. There are a few things I don't quite understand about the code samples you posted up, I'll try to translate into what I'd do and you can tell me if I'm doing it wrong :)
in your game class you need (and it looks like you have) a list of Missiles:
LinkedList<Batcher> missiles;
In your onTouch(), however a missile is created -
missiles.add(new Batcher(missilex, missiley, missile));
you now have a collection of missiles. Note that I didn't include the list in the constructor of your batcher, because an object should never need to know that it's a part of a collection. All it needs to know is how to draw itself and where. Since I assume that all of your missiles will be added to or removed from the screen frequently, while only having a few on screen at a time, I've used a LinkedList, which is fast for adding and removing, but slow for accessing a specific missile. If you needed to access specific items in the collection and the collection didn't change very much, you would use an ArrayList instead. on to onDraw - as you have it the missile draws itself, which is fine, but I prefer to let the View do the drawing, with the missile telling it where it should be drawn -
for (Batcher missile : missiles ){
missile.setX(missile.getX() + 14); // to make it move
if (missile.getX() > canvas.gedWidth()) { //check if it's left the screen
missiles.remove(missile); // Remove it
}
else { //perform drawing
canvas.drawBitmap(missile.getBitmap(), missile.getX(), missile.getY(), null);
}
}
Hopefully that'll do it for you, but feel free to let me know if there's anything you'd like me to explain more!

Has anyone done crosshairs that follow the mouse in JFreeChart?

We are using JFreeChart to make XY plots and we have a feature request to do a crosshair that moves along with the mouse and highlights the data point that most closely maps to the x-value of the mouse. You can see a similar example at Google Finance - http://www.google.com/finance?q=INDEXDJX:.DJI,INDEXSP:.INX,INDEXNASDAQ:.IXIC.
Those Google charts only highlight the current value (we want to do that and also show crosshairs), but they show the live mouse interaction we are looking for.
Anyone have any elegant suggestions?
Thanks.
I got this working using a mouse listener and the CrosshairOverlay class. After I get back from holiday travel, I will post my code. It ended up being not too difficult.
Sorry, I forgot about this!
First, you want to calculate the x, y values for where you want your crosshair. For me, I wanted it to move along the points of our line, so I calculated the closest x value and used that data pair for x, y.
Then I call this method:
protected void setCrosshairLocation(double x, Double y) {
Crosshair domainCrosshair;
List domainCrosshairs = crosshairOverlay.getDomainCrosshairs();
if (domainCrosshairs.isEmpty()) {
domainCrosshair = new Crosshair();
domainCrosshair.setPaint(BlueStripeColors.LIGHT_GRAY_C0);
crosshairOverlay.addDomainCrosshair(domainCrosshair);
}
else {
// We only have one at a time
domainCrosshair = (Crosshair) domainCrosshairs.get(0);
}
domainCrosshair.setValue(x);
if (y != null) {
Crosshair rangeCrosshair;
List rangeCrosshairs = crosshairOverlay.getRangeCrosshairs();
if (rangeCrosshairs.isEmpty()) {
rangeCrosshair = new Crosshair();
rangeCrosshair.setPaint(BlueStripeColors.LIGHT_GRAY_C0);
crosshairOverlay.addRangeCrosshair(rangeCrosshair);
}
else {
// We only have one at a time
rangeCrosshair = (Crosshair) rangeCrosshairs.get(0);
}
rangeCrosshair.setValue(y);
}
}
Note that crosshairOverlay is an instance of CrosshairOverlay.
JFreeChart can't render a sub-section of a chart, so you'll want to do something that doesn't require repainting the chart. You could write your chart to a BufferedImage and store that in memory, then have a custom component which uses the buffered chart as the background image, and draws crosshairs and other popup windows over it.
There are methods in JFreeChart to get the data point for a given coordinate on a rendered chart. Don't recall what these are off the top of my head. Depending on your needs, you might consider rendering your own chart data, it's not as hard as you'd think.
The first thing that comes to my mind would be to write a custom Cursor and set it on your chart. It can have a reference to the chart and highlight the x value that's consistent with the Cursor's x/y location.
This worked for me. I set the
chartPanel.addChartMouseListener(new ChartMouseListener() {
public void chartMouseMoved(ChartMouseEvent event)
{
try
{
double[] values = getCrossHairValue(event);
plot.clearRangeMarkers();
plot.clearDomainMarkers();
Marker yMarker = new ValueMarker(values[1]);
yMarker.setPaint(Color.darkGray);
plot.addRangeMarker(yMarker);
Marker xMarker = new ValueMarker(values[0]);
xMarker.setPaint(Color.darkGray);
plot.addDomainMarker(xMarker);
chartPanel.repaint();
} catch (Exception e)
{
}
}
}

Categories