I am currently trying to create a dodge-the-asteroid game in which the user controls a spaceship and tries to avoid the asteroids (3 kinds, small medium large). I currently have the animations all working (spaceship moving, asteroids falling). When the user presses start, the animation for randomly inserting asteroids begins:
public void startGame()
{
Timeline asteroids = new Timeline(new KeyFrame(Duration.seconds(.5), e -> displayAsteroid()));
asteroids.setCycleCount(Timeline.INDEFINITE);
asteroids.play();
}
Here is the code for creating the asteroids everytime the Timeline runs:
public void displayAsteroid()
{
// creates an asteroid object (constructor randomly creates one of 3 sizes)
Asteroid asteroid = new Asteroid();
getChildren().add(asteroid);
// randomly generates x coordinate from the board size
Random rand = new Random();
int randomNum = rand.nextInt((int) (getWidth() - asteroid.getWidth()));
//sets the x and y (y is -200 so that the asteroid doesn't just appear at top
// x is set to the random number
asteroid.setY(-200);
asteroid.setX(randomNum);
asteroid.setTranslateY(asteroid.getY());
asteroid.setTranslateX(randomNum);
// animation to move the asteroid down the screen
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(Duration.millis(50), event -> {
// checks if the asteroid leaves the screen or if collision happens
if(asteroid.getY() > getHeight() || spaceShip.intersects(asteroid.getBoundsInParent()))
{
timeline.stop();
getChildren().remove(asteroid);
}
else
{
// getSpeed is the speed of the asteroid (small is fastest, large is slowest)
asteroid.setY(asteroid.getY()+asteroid.getSpeed());
asteroid.setTranslateY(asteroid.getY());
}
});
timeline.setCycleCount(Animation.INDEFINITE);
timeline.getKeyFrames().add(keyFrame);
timeline.play();
}
The spaceship is a pane (bunch of rectangles/ellipses) stacked onto eachother, and the asteroids are also panes with random ellipses stacked ontop of a big ellipse (to make it look like an asteroid).
As of now, the collision does not work, as it will randomly delete one every now and then and I had a bunch disappear as I hit one of them - several times. How can I change this code up so it detects when the asteroid comes into contact with the ship?
Yes, I have looked at other questions, but they were normal objects such as circles, which is why I haven't been able to get mine to work. I can provide additional code (asteroid/spaceship classes) to help you test this out if needed
I feel the logic is wrong behind my code, and any help is greatly appreciated!
Thank you, have a nice day ! :)
Related
I tried to make a jump look realistic, while I watched through the Videos:
The Natur of Code - The Coding Train
I got into PVectors. I strongly recomend watching him. But to get to my question, everything seems to work, exept that it draws the rectangle (my PVector) the way I want.
void keyPressed() {
if (keyCode == UP) {
for (int i = 0; i < 16; i++) {
location.sub(velocity);
velocity.sub(acceleration);
h.display();
background(0);
}
velocity.set(0, 15);
}
}
That's the Code, I expect it to "jump", but nothing realy happens. You can see that the rectangle get's drawn again (on the same spot), but there's no movement. It's definitly an issue with the drawing of the background or something, I don't know what exaclty though.
The nature of your question is unclear. You mentioned issues regarding the background interfering with your rectangle after the UP arrow key is pressed. This is likely because background(0) is called immediately after h.display(). I would remove background(0) from your loop if it's a display issue.
Other than that, there seem to be other issues with the loop itself. When the UP key is pressed, h is affected by acceleration only for 16 frames. To make your object more realistic, gravity (or whatever acceleration you choose) should constantly be acting upon the object.
With that in mind, here's a solution for you.
void keyPressed() {
if (keyCode == UP) {
// Make the character 'jump' upwards when the UP arrow is pressed.
// Setting the velocity should be the only thing happening when the key is pressed.
velocity.set(0, -2);
}
}
void draw() {
// Reset the background each frame so rectangles don't overlap.
background(255);
// Always draw the rectangle AFTER resetting the canvas.
h.display();
// Change the object's location by it's velocity.
location.add(velocity);
// And chance the object's velocity by it's acceleration.
// Since acceleration is the acting force of gravity in this situation, acceleration need not be changed.
velocity.add(acceleration);
// Prevent the rectangle from falling through the bottom of the canvas.
if(location.y > height - 5) location.y = height - 5;
}
// You negleteced to define your variables in your code snippet. Here they are.
PVector location = new PVector(0, 0);
PVector velocity = new PVector(0, 0);
PVector acceleration = new PVector(0, 0.1); // Notice that acceleration's y-value is 0.01. This is so you can see the effect of gravity.
// Define your rectangle object.
Object h = new Object();
class Object {
Object() {} // Constructor.
void display() {
// Draw the rectangle at the x- and y-positions of the location vector.
// The '+ width/2' places it at the center of the screen.
rectMode(CENTER);
rect(location.x + width/2, location.y, 10, 10);
}
}
I am trying to store the motion detected from optical flow for frames in a video sequence and then use these stored motion vectors in order to predict the already known frames using just the first frame as a reference. I am currently using two processing sketches - the first sketch draws a motion vector for every pixel grid (each of width and height 10 pixels). This is done for every frame in the video sequence. The vector is only drawn in a grid if there is sufficient motion detected. The second sketch aims to reconstruct the video frames crudely from just the initial frame of the video sequence combined with information about the motion vectors got from the first sketch.
My approach so far is as follows: I am able to determine the size, position and direction of each motion vector drawn in the first sketch from four variables. By creating four arrays (two for the motion vector's x and y coordinate and another two for its length in the x and y direction), every time a motion vector is drawn I can append each of the four variables to the arrays mentioned above. This is done for each pixel grid throughout an entire frame where the vector is drawn and for each frame in the sequence - via for loops. Once the arrays are full, I can then save them to a text file as a list of strings. I then load these strings from the text file into the second sketch, along with the first frame of the video sequence. I load the strings into variables within a while loop in the draw function and convert them back into floats. I increment a variable by one each time the draw function is called - this moves on to the next frame (I used a specific number as a separator in my text-files which appears at the end of every frame - the loop searches for this number and then increments the variable by one, thus breaking the while loop and the draw function is called again for the subsequent frame). For each frame, I can draw 10 by 10 pixel boxes and move then by the parameters got from the text files in the first sketch. My problem is simply this: How do I draw the motion of a particular frame without letting what I've have blitted to the screen in the previous frame affect what will be drawn for the next frame. My only way of getting my 10 by 10 pixel box is by using the get() function which gets pixels that are already drawn to the screen.
Apologies for the length and complexity of my question. Any tips would be very much appreciated! I will add the code for the second sketch. I can also add the first sketch if required, but it's rather long and a lot of it is not my own. Here is the second sketch:
import processing.video.*;
Movie video;
PImage [] naturalMovie = new PImage [0];
String xlengths [];
String ylengths [];
String xpositions [];
String ypositions [];
int a = 0;
int c = 0;
int d = 0;
int p;
int gs = 10;
void setup(){
size(640, 480, JAVA2D);
xlengths = loadStrings("xlengths.txt");
ylengths = loadStrings("ylengths.txt");
xpositions = loadStrings("xpositions.txt");
ypositions = loadStrings("ypositions.txt");
video = new Movie(this, "sample1.mov");
video.play();
rectMode(CENTER);
}
void movieEvent(Movie m) {
m.read();
PImage f = createImage(m.width, m.height, ARGB);
f.set(0, 0, m);
f.resize(width, height);
naturalMovie = (PImage []) append(naturalMovie, f);
println("naturalMovie length: " + naturalMovie.length);
p = naturalMovie.length - 1;
}
void draw() {
if(naturalMovie.length >= p && p > 0){
if (c == 0){
image(naturalMovie[0], 0, 0);
}
d = c;
while (c == d && c < xlengths.length){
float u, v, x0, y0;
u = float(xlengths[a]);
v = float(ylengths[a]);
x0 = float(xpositions[a]);
y0 = float(ypositions[a]);
if (u != 1.0E-19){
//stroke(255,255,255);
//line(x0,y0,x0+u,y0+v);
PImage box;
box = get(int(x0-gs/2), int(y0 - gs/2), gs, gs);
image(box, x0-gs/2 +u, y0 - gs/2 +v, gs, gs);
if (a < xlengths.length - 1){
a += 1;
}
}
else if (u == 1.0E-19){
if (a < xlengths.length - 1){
c += 1;
a += 1;
}
}
}
}
}
Word to the wise: most people aren't going to read that wall of text. Try to "dumb down" your posts so they get to the details right away, without any extra information. You'll also be better off if you post an MCVE instead of only giving us half your code. Note that this does not mean posting your entire project. Instead, start over with a blank sketch and only create the most basic code required to show the problem. Don't include any of your movie logic, and hardcode as much as possible. We should be able to copy and paste your code onto our own machines to run it and see the problem.
All of that being said, I think I understand what you're asking.
How do I draw the motion of a particular frame without letting what I've have blitted to the screen in the previous frame affect what will be drawn for the next frame. My only way of getting my 10 by 10 pixel box is by using the get() function which gets pixels that are already drawn to the screen.
Separate your program into a view and a model. Right now you're using the screen (the view) to store all of your information, which is going to cause you headaches. Instead, store the state of your program into a set of variables (the model). For you, this might just be a bunch of PVector instances.
Let's say I have an ArrayList<PVector> that holds the current position of all of my vectors:
ArrayList<PVector> currentPositions = new ArrayList<PVector>();
void setup() {
size(500, 500);
for (int i = 0; i < 100; i++) {
currentPositions.add(new PVector(random(width), random(height)));
}
}
void draw(){
background(0);
for(PVector vector : currentPositions){
ellipse(vector.x, vector.y, 10, 10);
}
}
Notice that I'm just hardcoding their positions to be random. This is what your MCVE should do as well. And then in the draw() function, I'm simply drawing each vector. This is like drawing a single frame for you.
Now that we have that, we can create a nextFrame() function that moves the vectors based on the ArrayList (our model) and not what's drawn on the screen!
void nextFrame(){
for(PVector vector : currentPositions){
vector.x += random(-2, 2);
vector.y += random(-2, 2);
}
}
Again, I'm just hardcoding a random movement, but you would be reading these from your file. Then we just call the nextFrame() function as the last line in the draw() function:
If you're still having trouble, I highly recommend posting an MCVE similar to mine and posting a new question. Good luck.
I'm currently writing a android game and and am dealing with fast collision detections.
I've come up with a solution, yet I'd like to know the most and preferred way to do this.
My solution: If we have a game object that moves 30 units a frame, we might go straight through another game object. So when I update I iterate the game object by 1 unit and run a collision detections until my wanted velocity is reached, and then I render.
This is a game object, that checks if the player's lasers or if the player itself has collided with it.
public void update(PlayerDroid[] holderPlayerDroid) {
// Update the location
//y = y + velocity;
//stupidBadDroidPositionShape.setLocation(this.x, this.y);
// Updates regarding interactions with the enemy out of the StupidBadDroids perspective, which is the PlayeDroid
for(int numberOfPlayerDroid = 0; numberOfPlayerDroid < holderPlayerDroid.length; numberOfPlayerDroid++) {
// Check if the StupidBadDroid got hit
for(int iterations = 0; iterations < velocity; iterations++) {
y = y + 1;
stupidBadDroidPositionShape.setLocation(this.x, this.y);
// Check if StupidBadDroid collides with the enemy (which is the player)
if(Physics.shapeInShape(holderPlayerDroid[numberOfPlayerDroid].getPlayerPositionShape(), getPlayerPositionShape())) {
isDead = true;
}
for(int i = 0; i < holderPlayerDroid[numberOfPlayerDroid].amountOfVisibleLasers; i++) {
if(holderPlayerDroid[numberOfPlayerDroid].holderLaser[i].isDisposed() == false) {
if(Physics.shapeInShape(holderPlayerDroid[numberOfPlayerDroid].holderLaser[i].getLaserPositionShape(), getPlayerPositionShape())) {
isDead = true;
holderPlayerDroid[numberOfPlayerDroid].holderLaser[i].dispose();
}
}
}
}
}
}
This way is very CPU demanding. Do you believe there are better solution I could apply?
You are describing tunneling, and are attempting to do continuous collision detection. Your method is CPU intensive because you are attempting to brute-force the solution.
The more fidelity that you want, the more technical the solution. If you don't need much fidelity, you could assume that the path the objects take in each frame is linear, and "expand" your hitboxes to cover the entire distance the objects moved during the frame. So, for example, instead of moving each point a discrete distance at a time, you could simply expand the points to a line segment and see if they intersect. Your hitboxes are not going to be points, though, so just "stretch" them by the path length. This is a very low-fi solution - if multiple collisions on the same object happen, you won't always pick the collision that happened "first".
For very complex solutions, try -
http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Collision_Detection_and_Physics_FAQ
G'day All,
My little game has 5 bouncing balls and 1 player. Initially I wrote the code for the bouncing balls first and each ball has a collision detection method:
foreach (Bouncer bouncer in Game.Components) //For each bouncer component in the game...
{
if (bouncer != this)// Don't collide with myself
{
if (bouncer.collisionRectangle.Intersects(this.collisionRectangle))
{
// How far apart of the positions of the top right hand corners of the sprites when they hit?
int deltaX = Math.Abs((int)this.position.X - (int)bouncer.position.X);
int deltaY = Math.Abs((int)this.position.Y - (int)bouncer.position.Y);
// This is the width and height of a sprite so when two sprites touch this is how far the corners are from each other.
int targetWidth = 80;
int targetHeight = 80;
// The following determins the type of collision (vert hit vs horiz hit)
// Because the app is driven by a game based timer the actual amount of sprite overlap when the collision detection occurs is variable.
// This bit of simple logic has a 10 pixel tollerance for a hit.
// If target - delta is > 10 it will be interpreted as overlap in the non-colliding axis.
// If both if statements are triggered it is interpreted as a corner collision resulting in both sprites rebounding back along the original paths.
if (targetWidth - deltaX < 10) // The hit is a side on hit.
{
this.velocity.X *= -1;
}
if (targetHeight - deltaY < 10) // The hit is a vertical hit
{
this.velocity.Y *= -1;
}
this.numberOfCollisions = this.numberOfCollisions + 1;
}
}
}
base.Update(gameTime);
}
Then I added my player component and the wheels fell off. The app compiles OK but when I run it I get an InvalidCastException and the message:
Unable to cast object of type 'Bounce2.Player' to type 'Bounce2.Bouncer'.
I don't want to include the player object in this collision detector.
Is there a way I can enumerate my way through the Bouncer objects and exclude any other objects?
Thanks,
Andrew.
You can use this:
foreach (Bouncer bouncer in Game.Components.OfType<Bouncer>())
Note that you can store the Bouncer instances in other list too.
i want to create a game and addes a image to my game, now i want it to move down smoothly. i have a code like this:
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
pos.Y = pos.Y + 1;
base.Update(gameTime);
}
the movement works but it dont looks smooth, it looks like it jiggle. pos is a vector2 for the position in the image.
how to make it more smooth?
If you want movement to be smooth without adding a physics library you just have to factor in gameTime to your position update.
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
pos.Y = pos.Y * 100 * (float)gameTime.ElapsedGameTime.TotalSeconds;
base.Update(gameTime);
}
I don't have access to XNA + visual studio right now, but the changes I made should give you an idea of what to try out. Keep in mind the Update call happens multiple times a second so the elapsed time will be a small number so then you have to multiply it by a larger "movement" value in this case I put 100. Tweak 100 until you see the movement speed you desire.
Beanish is right, you should multiply by GameTime if you want smoothness. Physics is an overkill if you only want your animation to look smooth.
The best way I've found to do animation is by using position interpolation, for this to work you have to know the initial (you already know this) and final position of the image.
If you want to move from A to B in, say, 2 seconds, you can use the following code.
Vector2 a = new Vector2(0, 0);
Vector2 b = new Vector2(0, 100);
float elapsedTime = 0;
float duration = 2.0;
public override void Update(GameTime gameTime)
{
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
elapsedTime += dt;
if (elapsedTime > 1)
elapsedTime = 1;
float param = elapsedTime / duration;
pos = Vector2.Lerp(a, b, param);
}
The best thing about using this approach is that you can now use "easing" to make you animation look really really nice.
To do this just add a Power operation to the interpolator parameter:
pos = Vector2.Lerp(a, b, (float)Math.Pow(param /2.0, 0.5));
This will make you image slow down as it arrives to B. You can play with the exponent value (0.5) to get different results, try 2.0 for example.
Another important thing is that your image will always stop at B. If you use the Euler integration approach (your approach, adding a velocity each frame) you might have some trouble making the image stop at the right position (aka B) and it gets even worse when using 2 or 3 dimesions.
To know more about easing, check Robert Penner's Easing Equations.
First I can tell you what the problem isn't. You don't need a physics engine to have smooth movement. And changing the Update to include the ElapsedGameTime will not make a lick of difference for the smoothness (assuming you haven't changed the default of IsFixedTimestep to false). When there is a fixed timestep, ElapsedGameTime will always have the same value, it will not vary.
I don't how much you are doing in your code, but if it's too much, XNA will start skipping the Draw portion of your code, and this can definitely cause jerkiness. One way to check: in your Update method, test the value of IsRunningSlowly. Whenever it is true, XNA will skip some Draw calls.
If you are not doing anything complicated, then the culprit may be the refresh rate of your monitor. If it is set to anything other than 60Hz, you will have jerkiness. You could fix this by changing your monitor's refresh rate. Alternatively you can change the value of TargetElapsedTime to match your monitor's rate.
You should consider adding to your game a library for handling physics, as for example FarseerPhysics. By calculating the position in a per time base with physics rules applied your movements will be smooth and natural.