Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
It's my first time trying to create a 2d game in java and I made a little 8-bit like character that I want to put in place of the rectangle that appears on screen. I can't quite understand how to get the .png image into the rectangle's place, or how I would go about making the character, in this case, the image saved to my hard drive. Thanks!
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class Keying extends JPanel {
public Rectangle character;
public int charW = 24;
public int charH = 36;
public boolean right = false;
public boolean left = false;
public boolean up = false;
public boolean down = false;
public Keying(Display f, Images i)
{
character = new Rectangle(180, 180, charW, charH);
f.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_D)
{
right = true;
}
if (e.getKeyCode() == KeyEvent.VK_A)
{
left = true;
}
if (e.getKeyCode() == KeyEvent.VK_S)
{
down = true;
}
if (e.getKeyCode() == KeyEvent.VK_W)
{
up = true;
}
}
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_D)
{
right = false;
}
if (e.getKeyCode() == KeyEvent.VK_A)
{
left = false;
}
if (e.getKeyCode() == KeyEvent.VK_S)
{
down = false;
}
if (e.getKeyCode() == KeyEvent.VK_W)
{
up = false;
}
}
});
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.white);
g.setColor(Color.black);
g.fillRect(character.x, character.y, character.width, character.height);
if (right)
{
character.x += 1;
}
if (left)
{
character.x -= 1;
}
if (down)
{
character.y += 1;
}
if (up)
{
character.y -= 1;
}
repaint();
}
}
The process is relatively simple...
Start by loading the character image...
public class Keying extends JPanel {
//public Rectangle character;
private java.awt.BufferedImage character;
private java.awt.Point characterLocation;
//...
public Keying(Display f, Images i) throws IOException
{
character = javax.ImageIO.read(...);
characterLocation = new Point(0, 0);
//...
See Reading/Loading an Image for more details...
Then, you simply want to paint the character image...
#Override
protected void paintComponent(Graphics g)
{
g.drawImage(character, characterLocaiton.x, characterLocation.y, this);
Advice
Avoid KeyListener, it's prone to focus issues you really don't want to deal with. Instead use key bindings, see How to Use Key Bindings for more details
Avoid putting any logic within any of the paint routines, painting can occur at any time, many of which you don't control, this could have your character moving in directions you don't expect or faster than they should. Instead, this belongs within the main game loop which is responsible for updating the state and scheduling paint requests.
NEVER change the state of the component from within any paint method, this could cause an infinite loop of paint requests, which will consume your systems resources. Within your context, don't call setBackground (by the time you call this, the background has already been painted anyway) or repaint
Related
I am trying to do a PAC-MAN clone in Java. I am using swing and awt for the GUI.
I implemented motion into my main character and it responds to keys pressed, but when the character moves the "old image" stays there. So, rather than it looking like pacman moves through the screen he leaves a trail. It is my understanding that when I use the repaint() function the image should be cleared and painted again.
This is my code:
//PACMAN CLASS
import Entities.Ghost;
import Entities.Player;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Pacman extends JPanel implements KeyListener {
Player player = new Player("Pacman.png", 0, 0);
Ghost[] ghosts = new Ghost[4];
public Pacman(){
addKeyListener(this);
setFocusable(true);
ghosts[0] = new Ghost("Ghost_Red.png", 200, 200);
ghosts[1] = new Ghost("Ghost_Red.png", 150, 150);
ghosts[2] = new Ghost("Ghost_Red.png", 300, 100);
ghosts[3] = new Ghost("Ghost_Red.png", 50, 300);
}
public void paintComponent(Graphics g){
player.draw(g, this);
for(Ghost ghost: ghosts){
ghost.draw(g, this);
}
}
public void update() {
repaint();
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER){
new Thread( () -> {
while (true){
update();
try{
Thread.sleep(10);
}catch(InterruptedException err){
err.printStackTrace();
}
}
}).start();
}
int SPEED = 4;
if(e.getKeyCode() == KeyEvent.VK_RIGHT && player.x < (getWidth() - player.width)){
player.x += SPEED;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT && player.x > 0){
player.x -= SPEED;
}
if(e.getKeyCode() == KeyEvent.VK_UP && player.y > 0){
player.y -= SPEED;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN && player.y < (getHeight() - player.height)){
player.y += SPEED;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
//MY MAIN
import javax.swing.*;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Pacman");
Pacman panel = new Pacman();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(224*2,288*2);
frame.setResizable(false);
}
}
I followed a tutorial to get here and the guy's graphic do work properly. Thoug he is using JAva 10 and I am using Java 16
When doing custom painting, and especially when doing some "animations", it's really important to call super.paintComponent(g); as the first line in your paintComponent(...) method
This will repaint all the things you're not painting on that "frame", and thus this is what you need to do to solve your problem.
If you want to know more in detail what super.paintComponent() does, then read this answer.
So your code should end up looking like this:
public void paintComponent(Graphics g) {
super.paintComponent(g);
player.draw(g, this);
for(Ghost ghost : ghosts) {
ghost.draw(g, this);
}
//Any extra painting do it here
}
Also, this line:
frame.setVisible(true);
Should be the last one on your program
And about this line:
frame.setSize(224*2,288*2);
Better override your JPanel's getPreferredSize, and then call frame.pack() this will make your pane to have that size and then add the frame decorations, otherwise your panel will be smaller than you think it is; for more information take a look at this question and answers: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
And as a tip, don't use "magic numbers", instead declare constants as of what those 224 and 288 means and why you multiply them by 2.
And forgot to mention that when programming games, it's better to use KeyBindings rather than infinite loops (while(true)) with KeyListeners; here's an excellent answer from #HovercraftFullOfEels that shows how to do it.
I am attempting to create my own version of the well known game Space invaders. I am using zetcode as a point of reference (not a direct copy and paste) http://zetcode.com/tutorials/javagamestutorial/spaceinvaders/
However I seem to be a bit stuck. Namely on the use of KeyAdapters and the MVC design pattern. According to zetcode tutorial, the protected int dx changes when KeyPressed is pressed and once again when it is released, however I not seeing any movement nor value change outside of the KeyPressed and Keyreleased methods.
I carried out some simple checks
1: Does the "player" graphics move without key input at all (basically do graphic updates work)? - Yes, I changed the "move()" method within player to simply do a "x--; " and visibly see movement on screen
2: Does the value "dx" change at all? - Kinda, from Keypressed method, I can use System.out.println(""+dx); to return the value and visibly see, from within the method that dx changes, but not outside of this method, suggesting that the value changes are only occurring local to this method, which in my opinion is bizarre.
My ask from the community is the following:
Is this an issue with concurrency (or should I say, 2 references to the "dx" value stored in memory but only 1 reference is getting updated or there something else funky going on in my code that I am missing?
package spaceInvaders;
import java.awt.event.KeyEvent;
public class Player extends IngameObjects implements Commons {
private int startX = 250;
private final int startY = 150;
public Player(){
initPlayer();
}
public void initPlayer(){
this.setX(startX);
this.setY(startY);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public void move(){
this.x += dx;
if (x <= 2) {
x = 2;
}
if (x >= 400 - 2 * 10) {
x = 400 - 2 * 10;
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT){
dx = -1;
System.out.println(""+dx);
}
if(key == KeyEvent.VK_RIGHT){}
if(key == KeyEvent.VK_ESCAPE){
System.exit(0);
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT){
this.x = -1;
}
if(key == KeyEvent.VK_RIGHT){}
}
}
package spaceInvaders;
public class IngameObjects {
protected int x;
private int y;
protected int dx;
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
package spaceInvaders;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable{
private Player player;
private Thread animator;
private boolean isRunning;
public GamePanel(){
this.setBackground(Color.BLACK);
this.setDoubleBuffered(true);
addKeyListener(new TAdapter());
setFocusable(true);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
drawPlayer(g);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void drawPlayer(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(player.getX(), player.getY(), 50, 50);
}
#Override
public void run() {
isRunning = true;
long startTime, timeDiff, sleepTime;
startTime = System.currentTimeMillis();
while(isRunning){
repaint();
gameUpdate();
timeDiff = System.currentTimeMillis() - startTime;
sleepTime = 5 - timeDiff;
try{
Thread.sleep(sleepTime);
}
catch(InterruptedException ex){
System.exit(0);
}
startTime = System.currentTimeMillis();
}
}
#Override
public void addNotify(){
super.addNotify();
startGame();
}
public void startGame(){
player = new Player();
if(animator == null || !isRunning){
animator = new Thread(this);
animator.start();
}
}
public void gameUpdate(){
player.move();
}
private class TAdapter extends KeyAdapter{
#Override
public void keyPressed(KeyEvent e) {
System.out.println(""+player.getX());
player.keyPressed(e);
}
#Override
public void keyReleased(KeyEvent e) {
player.keyReleased(e);
}
}
}
thanks for the swift responses, much appreciated. After x amount of time (leaving it as x due to embarrassment) I have actually found a problem, quite a serious one actually.
1: Duplicated TAdapter on another class which extended the JFrame
2: 2 classes (GamePanel (which extends JPanel) and class (poorly named) Main (which extends JFrame) both have setFocusable(true);
Regarding Vince's reply, yes you are correct, as an attempt to debug my own code I actually replaced what was originally dx, for x. Obviously neither worked which led me to suspect there was a coding issue elsewhere.
Regarding MadProgrammer's reply, thanks, I am not familiar with Key bindings, I have not been programming in a very long time, which is the reason why I am making my own version of space invaders, so I can not only get back into programming but improve my knowledge, I will look at key bindings, even though you don't specify what is wrong with KeyListeners, I will study the differences. Regarding dispose, yep once again, not very familiar with the uses, i thought it was another way of refreshing the graphics, I will look into this.
in summary, where did I go wrong:
Duplicated TAdapter in a dedicated class for JFrame and another one
in JPanel
Duplicated requests for "focus" setFocusable(true);
Use KeyListener instead of key bindings (not sure why: research required)
Use of the dispose() method
Changing value of x rather than dx
This question can be considered resolved at this point, thanks
I am making a classic space shooter type game for a GUI project, using JPanels and swing etc. I have a multi-layered main menu with a button for play and exit etc, however, the issue I am having is in my DrawPanel class which paints all the graphics for the game. This class has one giant paint component method that activates on a timer every 500 ms, and renders blinking stars on a background, renders the spaceship, and renders falling enemies. The stars are blinking, the enemies are falling but the spaceship is not moving at all and I have to use the "a" and "d' keys. The question: how can I move the ship? Below is an extremely summarized version of that rendering class to keep it simple, the paint component class is full of other things however including generating blinking stars.
public DrawPanel(int x, int y)
{
t = new Timer(500, new ActionListener(){#Override public void actionPerformed (ActionEvent event){repaint();}});
this.addKeyListener(new KeyAdapter()
{
#Override public void keyPressed(KeyEvent e) { ship.keyPressed(e);System.out.println("keypressed");}
#Override public void keyReleased(KeyEvent e) { ship.keyReleased(e);System.out.println("keyreleased");}
});
t.start();
}
public void paintComponent(Graphics Graphic)
{
super.paintComponent(Graphic);
drawShip(Graphic);
drawEnemy(Graphic,10);
}
private void drawShip(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(ship.getImage(), ship.getX(),
ship.getY(), this);
}
This is the spaceship class that is called by the drawship method, and that explains the calls by variable "ship" in the previous code.(Note: there are no compiler errors or runtime errors in anything)
public class Spaceship {
private int x = 780;
private int y = 850;
private Image image;
public Spaceship()
{
ImageIcon ii = new ImageIcon("spaceship.png");
image = ii.getImage();
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key ==KeyEvent.VK_A) {
x += -10;
}
if (key == KeyEvent.VK_D) {
x+= 10;
}
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_A) {
x += 0;
}
if (key == KeyEvent.VK_D) {
x += 0;
}
}
}
My thought process on this was that the keyboard would be active at all times and anytime it registered a press it would modify an x so that the next time the ship would be drawn it would be in a different position. However it would be bound by the same time that the enemies and background are bound by and wouldn't fluidly move side to side now that I think about it, but I have no clue how to make a separate paint component, timer, and repaint as that's the only way I know to paint. Also
I do realize I haven't done bound checking on this for the ship movement but that shouldn't be an issue right now as it's not even moving a centimeter yet, much less out of bounds, and it is not even printing the debug statements in the listener.
All of my classes are added to panels which have been bound to buttons and tabs in my main menu by adding it all to default constructor of the main method, so this is how the entire game executes:
public static void main(String[] args) throws IOException
{
GalagaRipOff main = new GalagaRipOff();
}
Please excuse my bad english. I am having a problem while implementing a 2d camera. I made the camera to follow the player until it reaches near the edge of the game-level, where only the player moves and the camera stops. I made this easily but my problem is that the camera is not proper. The camera continues to move 1 extra pixel every time you reach at the edge of the game-level limit in all four directions (The code I posted only shows horizontal movement. This I did for simplicity). This means if you move 40 times to and fro near the left edge of the game, camera will move 40 extra pixels right! I have no idea how to solve this.
I posted a very simplified version from my original code below and made it as small as i could to show how the program works. Following just moves the player and camera horizontally across the screen.
This is 'theGamePanel' class (it is the main class) :-
public class TheGamePanel extends JPanel implements Runnable, KeyListener
{
private boolean left, right;
private float cameraX, cameraY;
private World world = new World();
private Player player = new Player();
public TheGamePanel()
{
//setting the size of panel
}
public static void main(String[] args)
{
//setting the window
}
public void paint(Graphics g)
{
super.paint(g);
// drawing the game-level and player
g.translate((int)cameraX, (int)cameraY);
world.paint(g);
player.paint(g);
g.translate(-(int)cameraX, -(int)cameraY);
}
public void upd()
{
player.update(left, right, this);
}
#Override
public void run()
{
// game-loop
}
#Override
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if(code == KeyEvent.VK_LEFT)
{
left = true;
}
if(code == KeyEvent.VK_RIGHT)
{
right = true;
}
}
#Override
public void keyReleased(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_LEFT)
{
left = false;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
{
right = false;
}
}
#Override
public void keyTyped(KeyEvent e)
{
}
//to set camera position
public void setCameraX(float cameraDx)
{
cameraX += cameraDx;
}
}
This is the 'Player' class. This class is where the player and camera movement takes place. The camera's x and values are then returned to 'TheGamePanel' :-
public class Player
{
private float x, y;
private float dx = 1;
private int width = 32, height = 32;
private float leftLimit, rightLimit;
public Player()
{
//player's initial x and y coordinates
x = 320;
y = 240;
//camera's limit (where the camera needs to stop following player)
leftLimit = x;
rightLimit = 960;
}
public void paint(Graphics g)
{
//for painting the player
g.setColor(Color.GREEN);
g.fillRect((int)x, (int)y, width, height);
}
//to move player and camera
public void update(boolean left, boolean right, TheGamePanel panel)
{
if(left == true)
{
x -= dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(dx);
}
}
if(right == true)
{
x += dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(-dx);
}
}
}
}
And lastly, the 'World' class. This class is used to simply paint a big map(level) in the background :-
public class World
{
private BufferedImage map;
private int tileWd = 32, tileHi = 32;
public World()
{
try
{
map = ImageIO.read(new File("map1.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void paint(Graphics g)
{
//simply paints a game-level in the background
}
}
If anything not understandable please tell. I will add more details.
Consider the case where the player is standing near the right edge of the map. One quick tap on the "right" key moves him out of the camera-follow area so the camera doesn't move. One quick tap on the "left" key moves him back into the camera-follow area. The camera will be moved "dx" units to the left. This will have the effect of the player slowly creeping closer to the right edge of the playing field, if I'm correct.
(To find bugs like this, I generally litter the code with System.out.println messages. If there's a lot of messages, I write them to a file and do text searches on keywords)
you have a location for your camera (cameraX,cameraY) but nothing for the player?
just create a location for player (playerX,playerY)
change the paint like:
public void paint(Graphics g)
{
super.paint(g);
// drawing the game-level and player
g.translate((int)cameraX, (int)cameraY);
world.paint(g);
g.translate((int)playerX, (int)playerY);
player.paint(g);
g.translate(-(int)(playerX+cameraX), -(int)(playerY+cameraY));
}
and when player come near borders don't move camera and only player.
I believe the following change fixes the problem:
Player class:
//to move player and camera
public void update(boolean left, boolean right, TheGamePanel panel)
{
if(left == true)
{
x -= dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(dx);
}
}
if(right == true)
{
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(-dx);
}
x += dx; // Only change: moved this line AFTER the if block
}
}
By testing x after changing it when moving left and before changing it when moving right you compensate for the error that was otherwise accumulating every time you reached one of the boundaries.
Anyway I suggest you to change your approach to the problem in order to make your code easier to maintain and more flexible. One way to do that is to calculate the camera position based on current player's position on every frame.
Note: The line g.translate(-(int)cameraX, -(int)cameraY); in the paint() method of TheGamePanel class is unnecessary once the method translate(int, int) is not incremental.
Regards
I have just started learning java and I've been working on this code for a moving object with keyboard input. I am now trying to add in a background, but it keeps erroring with:
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at game.GameLoop.run(GameLoop.java:24)
at java.lang.Thread.run(Unknown Source)
The code I have in Game.java is:
package game;
import java.applet.*;
import java.awt.*;
public class Game extends GameLoop{
public void init(){
setSize(864,480);
Thread th = new Thread(this);
th.start();
offscreen = createImage(864,480);
d = offscreen.getGraphics();
addKeyListener(this);
}
public void paint(Graphics g){
d.clearRect(0, 0, 864, 480);
d.drawImage(background, 0, 0, this);
d.drawRect(x, y, 20, 20);
g.drawImage(offscreen, 0, 0, this);
}
public void update(Graphics g){
paint(g);
}
}
And here is my GameLoop.java:
package game;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class GameLoop extends Applet implements Runnable, KeyListener{
public int x, y;
public Image offscreen;
public Graphics d;
public boolean up, down, left, right;
public BufferedImage background;
public void run(){
x = 100;
y = 100;
try {
background = ImageIO.read(new File("background.png"));
} catch (IOException e1) {
e1.printStackTrace();
}
while(true){
x = 100;
y = 100;
while(true){
if (left == true){
x-=4;
}
if (right == true){
x+=4;
}
if (up == true){
y-=4;
}
if (down == true){
y+=4;
}
if ( x <= 0 ){
x = 0;
}
if ( y <= 0 ){
y = 0;
}
if ( x >= 843 ){
x = 843;
}
if ( y >= 460 ){
y = 459;
}
repaint();
try{
Thread.sleep(20);
} catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
//#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 37){
left = true;
}
if(e.getKeyCode() == 38){
up = true;
}
if(e.getKeyCode() == 39){
right = true;
}
if(e.getKeyCode() == 40){
down = true;
}
}
//#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == 37){
left = false;
}
if(e.getKeyCode() == 38){
up = false;
}
if(e.getKeyCode() == 39){
right = false;
}
if(e.getKeyCode() == 40){
down = false;
}
}
//#Override
public void keyTyped(KeyEvent e) {
}
}
Sorry about the editing I can't seem to get it all in the ``, and I will also fix the messy code, but do you guys have any ideas what is causing this error, there is a file in the src dir called background.png, it is very basic and made in MS paint, if that helps.
Thanks.
There are two places a simple, sand-boxed applet can obtain images.
Where
A loose file on the same server the applet was supplied from. E.G. This might be used for a sand-boxed 'image slideshow' where the image names are supplied in applet parameters.
A Jar on the run-time class-path of the applet. Best for resources which would not typically change (barring localized images, where it becomes more complicated). E.G. This might be used for button/menu icons, or BG images.
"background.png" strongly indicates the 2nd scenario - 'part of the app. itself'.
How to find
Both types of resources should identified by URL (do not try to establish a File as it will fail when the applet is deployed).
The way to obtain an URL for the 2nd case is something along the lines of:
URL urlToBG = this.getClass().getResource("/path/to/the/background.png");
..where /path/to/the/ might simply be /resources/ or /images/. It is the path within a Jar on the classpath, where the image can be found.
How to load
Most methods that will load a File are overloaded to accept an URL. This notably applies to ImageIO.read(URL).
While the Applet class has inbuilt methods to load images, I recommend sticking with ImageIO since it provides more comprehensive feed-back on failure.
Further tips
Tip 1
Thread.sleep(20);
Don't block the EDT (Event Dispatch Thread) - the GUI will 'freeze' when that happens. Instead of calling Thread.sleep(n) implement a Swing Timer for repeating tasks or a SwingWorker for long running tasks. See Concurrency in Swing for more details.
Tip 2
It is the third millennium, time to start using Swing instead of AWT. That would mean extending JApplet instead of Applet. Then you might shift the logic of painting into a JPanel that is double-buffered by default, and could be used in either the applet or a frame (or a window or a dialog..).
Tip 3
setSize(864,480);
The size of an applet is set in HTML, and the applet should accept whatever size it is assigned and work within that. Taking that into account, statements like:
d.clearRect(0, 0, 864, 480);
..should read more like:
d.clearRect(0, 0, getWidth(), getHeight());
#Patricia Shanahan Your comment actually helped me to solve the same problem.
I've used that code:
File here = new File(".");
try {
System.out.println(here.getCanonicalPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
and from there you can figure out the correct path to use.