I am having a rectangle which should represent a car. It should rotate when you tuch the display. How to make this with box2d. I already setted all up: Press W to accelerate and touch display for right turn and dont touch it for left turn. Problem is that the car is drifting when you rotate it and not immediately goes only to the direction its facing to. So far this is my code, how to remove this drifting, its like it drives on ice. :/
EDIT: (copied from C++ code: http://www.iforce2d.net/b2dtut/top-down-car I tried to copy everything until the Torque so now It should drive. But when I do accelerate. It does not move. The currentSpeed Variable is 0 and the currentForwardNormal is 0.0 ,0.0. What did I wrong?)
//Main upate
public void update(float delta) {
updateFriction();
}
//Movements and Subclasses of them
public void accelerate() {
//find current speed in forward direction
Vector2 currentForwardNormal = ship.getWorldVector(new Vector2(0,1));
float currentSpeed = getForwardVelocity().dot(currentForwardNormal);
//apply necessary force
float force = 0;
if(maxSpeed > currentSpeed) {
force = maxDriveForce;
} else {
force = -maxDriveForce;
}
System.out.println("Current Speed: "+currentSpeed);
System.out.println("Current Forward Normal: "+currentForwardNormal);
ship.applyForceToCenter(currentForwardNormal.scl(force),true);
}
public void rotate(boolean direction) { //true for Up and false for Down
if(direction) {
//torques
}
}
private void updateFriction() {
Vector2 impulse = getLateralVelocity().scl(-ship.getMass());
ship.applyLinearImpulse(impulse, ship.getWorldCenter(), true);
ship.applyAngularImpulse(0.1f * ship.getInertia() * -ship.getAngularVelocity(),true);
}
private Vector2 getLateralVelocity() {
Vector2 currentRightNormal = ship.getWorldVector(new Vector2(1,0));
return currentRightNormal.scl(currentRightNormal.dot(ship.getLinearVelocity()));
}
private Vector2 getForwardVelocity() {
Vector2 currentRightNormal = ship.getWorldVector(new Vector2(0,1));
return currentRightNormal.scl(currentRightNormal.dot(ship.getLinearVelocity()));
}
Related
I am working on a 2D platformer game for my, last, HS year project.
The game is basically about a player walking back & forward, collecting points and reaching goals... The player can shoot bullets and when bullets hit a block, it is destroyed. Now, I wanted to add an explosion effect using so called "particle" objects. I have written the manager class for it and it seemed to have worked the first time but after shooting a few times, i noticed that the particles stopped getting deleted, they just continue and travel out of screen. The life-time limit is 500ns.
I have also noticed that if i shoot bullets as soon as the game starts, the effect finishes as it is supposed to. but after waiting for a few more seconds and then shooting bullets, the effect particles do not behave as they should.
Here is what it looks like when i shoot bullets as soon as i start the game (What it's supposed to look like):
and here is what it looks like, after waiting a few seconds before shooting the bullets.
ParticleManager.java
public class ParticleManager {
private ArrayList<Particle> particles;
private ArrayList<Particle> removeParticles;
public ParticleManager() {
particles = new ArrayList<Particle>();
removeParticles = new ArrayList<Particle>();
}
public int getListSize() {
return particles.size();
}
/*
Generate particles
*/
public void genParticle(int x, int y, int amount) {
for(int i = 0; i < amount; i++) {
particles.add(new Particle("explosion" , x,y, i));
}
}
public void update() {
// Iterate trough particle objects
// update them & check for lifeTime
for(Particle p: particles) {
// Updating particle object before
// checking for time lapse
p.update();
// Append outdated particles to removeParticles
// if time limit has passed
if(System.nanoTime() - p.timePassed >= Config.particleLife) {
removeParticles.add(p);
}
}
// finally, delete all "remove-marked" objects
particles.removeAll(removeParticles);
}
public void render(Graphics2D g) {
for(Particle p: particles) {
p.render(g);
}
}
}
Particle.java
class Particle {
private double px, py, x, y;
private int radius, angle;
public long timePassed;
String type;
public Particle(String type, double x, double y, int angle) {
this.x = x;
this.y = y;
this.radius = 0;
this.angle = angle;
this.timePassed = 0;
this.type = type; // explosion, tail
}
public void update() {
px = x + radius * Math.cos(angle);
py = y + radius * Math.sin(angle);
radius += 2;
this.timePassed = System.nanoTime();
}
public void render(Graphics2D g) {
g.setColor(Color.WHITE);
g.fillOval((int)px, (int)py, 5, 5);
}
}
I haven't figured out what I am doing wrong here, I've googled about some stuff and at one point i came across an answer mentioning that some references don't get deleted directly for some reason...
and my question is "How can I make these particles vanish after a certain amount of time has passed? - as shown in the first GIF"
I think the problem is that you are constantly overwriting timePassed.
// Updating particle object before
// checking for time lapse
p.update();
// Append outdated particles to removeParticles
// if time limit has passed
if(System.nanoTime() - p.timePassed >= Config.particleLife) {
removeParticles.add(p);
}
p.update() sets timePassed to now and then the if check checks if time passed is far from now (it will never be since it was just set).
I think you do want to set timePassed in the constructor (maybe it would be better named timeCreated).
Additionally, just a heads up, you never clear removeParticles so that list is going to grow forever until it causes the process to run out of memory.
What the title says. Is it possible?
As far as I know, there is no getKeyPressed or anything of the sort. I want to use a switch case for organization (and practice) as well as speed (or so I was informed).
Basically, the switch case clause(?) is just a boolean return. But how can I check if a key is pressed based on a value passed into it without a pasta bowl of if / else statements?
Obviously this code doesn't work, but I'm looking for something like it.
public void moveCamera() {
switch (Keyboard.isKeyDown(!!!CASE CHECKING HERE!!!)) {
case Keyboard.KEY_W:
position.z -= MOVE_SPEED;
break;
case Keyboard.KEY_A:
position.x += MOVE_SPEED;
break;
case Keyboard.KEY_S:
position.z -= MOVE_SPEED;
break;
case Keyboard.KEY_D:
position.x += MOVE_SPEED;
break;
}
}
Here is a solution that I liked (but did not try) from #KysonTyner.
You can switch on getEventKey(). This will hit your current cases and then you can wrap the whole switch statement with if (getEventKeyState()) {switch/case}. There is no need to use an event listener. – Kylon Tyner
As for what I used, I abandoned the idea of a switch entirely, as I realized that the movement speed would multiply if there were more than one direction of input.
I wanted to support multiple directions of motion for diagonal movement, so it wouldn't be "ghosting" as keys were pressed.
What I did is separate the functions, one to test keyboard input, and one to move the camera. There doesn't have to be any special logic for the key input, as it simply passes an LWJGL Vector3f to the camera move function.
Then, in camera move, I normalized that vector and altered the positions accordingly.
This is a simplified version of my Camera class for demonstration. I removed everything except translation.
package spikespaz.engine.main;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.vector.Vector3f;
// Created by spike on 7/3/2017.
public final class Camera {
private Camera() {}
private float moveSpeed = 0.2f;
private Vector3f position = new Vector3f(0, 0, 0);
public Camera(Vector3f position, Vector3f rotation) {
this.position = position;
}
public void updateKeyInput() {
Vector3f direction = new Vector3f(0, 0, 0);
if (Keyboard.isKeyDown(Keyboard.KEY_W)) {
direction.x = 1;
} else if (Keyboard.isKeyDown(Keyboard.KEY_S)) {
direction.x = -1;
}
if (Keyboard.isKeyDown(Keyboard.KEY_SPACE)) {
direction.y = -1;
} else if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
direction.y = 1;
}
if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
direction.z = 1;
} else if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
direction.z = -1;
}
translate(direction);
}
private void translate(Vector3f direction) {
Vector3f normalized = direction.normalise(null);
Vector3f.add(position, (Vector3f) normalized.scale(moveSpeed), position);
}
public float getMoveSpeed() {
return moveSpeed;
}
public void setMoveSpeed(float moveSpeed) {
this.moveSpeed = moveSpeed;
}
}
Translate is relative. In the full class I have another function to set absolute position, without the move speed.
In the above example, the input vector for translate is simply a direction. The function should coordinate that based on the movement speed for each frame.
I'm having an issue showing that one rectangle has collided with another. So my question is, how can I get the intersect method to check for collision? Or are there any other ways to handle collision in this situation?
I'm creating a turn-based combat game (similar to Final Fantasy or Legend of Dragoon) where the player's character is on the right side of the screen and the enemy is on the left side. The player and enemy each take turns attacking. So when the player attacks, the sprite animation moves across the screen from right to left until it stops in front of the enemy, attacks, and returns to it's starting coordinates. Both the player and enemy have a rectangle drawn around them to represent the bounds of each character.
When the player moves forward, he passes through the Enemy's rectangle and stops within it. At this point there should be output to the console saying "INTERSECT!" to show that there was a collision between the two rectangles, but unfortunately there isn't.
Please note that I have omitted the unnecessary pieces of code within my classes and tried to provide the code that pertains to my problem.
This is my entry point, GameClass:
public class GameClass extends BasicGame{
//other variable declarations
public void init(GameContainer container) throws SlickException {
player = new Player();
enemy = new Enemy();
skeleton = new Skeleton();
enemy = skeleton;
playX = player.getStartX(); //700
playY = player.getStartY(); //140
playW = player.rect.getWidth(); //40
playH = player.rect.getHeight(); //70
enemyX = enemy.getStartX(); //100
enemyY = enemy.getStartY(); //140
enemyWidth = enemy.getWidth(); //50
enemyHeight = enemy.getHeight(); //55
SpriteSheet sheet = new SpriteSheet("data/homeranim.png", 36, 65);
anim = new Animation();
for (int i=0;i<8;i++) {
anim.addFrame(sheet.getSprite(i,0), 150);
}
}
public void render(GameContainer container, Graphics g)
throws SlickException {
anim.draw(playX,playY); // draws player animation
skeletonAnim.draw(enemyX, enemyY); // draws enemy
g.draw(player.rect); //draws player bounds
g.draw(enemy.rect); //draws enemy bounds
}
public void update(GameContainer container, int delta)
throws SlickException {
playerUpdate(delta);
if (player.rect.intersects(enemy.rect)) {
System.out.println("INTERSECT!");
System.out.println("Player minX: " + player.rect.getMinX());
System.out.println("Player maxX: " + player.rect.getMaxX());
System.out.println("Enemy minX: " + enemy.rect.getMinX());
System.out.println("Enemy maxX: " + enemy.rect.getMaxX());
}
}
public void playerUpdate(int delta) {
if (playerForward == true){
playX -= delta * 0.4f;
if (playX <= 140) {
playX = 140;
playerForward = false;
playerBackward = true;}
}
if (playerBackward == true) {
playX += delta * 0.4f;
if (playX >= 700) {
playX = 700;
playerBackward = false;
delay = 1250;
}
public void keyReleased(int key, char c) {
if (key == Input.KEY_ENTER){
playerForward = true;}
}
}
This is a glimpse at my Player class:
public class Player {
private int startX = 700;
private int startY = 140;
public Shape rect = new Rectangle(startX, startY, 40, 70);
//plus getters and setters
}
And my entire Enemy class:
public class Enemy {
private int startX, startY, width, height;
public Shape rect = new Rectangle(startX, startY, width, height);
// plus getters and setters
}
My Skeleton class extends Enemy:
public class Skeleton extends Enemy {
public Skeleton() {
// TODO Auto-generated constructor stub
setMaxHealth(120);
setStartX(100);
setStartY(140);
setWidth(50);
setHeight(55);
}
}
Note: Since I've switched g.drawRect() to g.draw(), enemy rectangle isn't being drawn.
Rect bounds at starting point: http://i.imgur.com/QDDk858.png
Rect bound where collision should be: http://i.imgur.com/pOANfvN.png
I hope I've provided enough code to show you what my problem is. I've rummaged through the internet for hours with no luck. If there is any other code I need to provide, please do not hesitate to ask. Thank you very much for your help and support!
You are not updating the hitbox positions themselves.
You are drawing this:
g.drawRect(playX, playY, playW, playH); //draws player bounds
g.drawRect(enemyX, enemyY, enemyW, enemyH); //draws enemy bounds
But this isn't the actual hitbox, it's just the position of the player/enemy and the rectangles drawn here will be on the correct position while the hitboxes themselves aren't.
I suggest you do the following:
public void update(GameContainer container, int delta)
{
playerUpdate(delta);
player.rect.setLocation(playX, playY);
enemy.rect.setLocation(enemyX, enemyY); // update the hitboxes to the new positions
if (player.rect.intersects(enemy.rect))
{
System.out.println("INTERSECT!");
}
}
public void playerUpdate(int delta)
{
if (playerForward == true)
{
playX -= delta * 0.4f;
if (playX <= 140)
{
playX = 140;
playerForward = false;
playerBackward = true;
}
}
if (playerBackward == true)
{
playX += delta * 0.4f;
if (playX >= 700)
{
playX = 700;
playerBackward = false;
delay = 1250;
}
}
}
public void keyReleased(int key, char c)
{
if (key == Input.KEY_ENTER)
{
playerForward = true;
}
}
Furthermore, as you seem to be new to game development in Java, some tips for you:
Format your code properly
Always place full {...} after if, else, switch, while, for, etc.; proper line indentation, .
Think OO (Object-Oriented)
This one is pretty important. Your enemy and player class should both extend some kind of entity class because they both will pretty much want to obtain similar behavior (avoid code duplication!). Sum up similar behavior to a super class, simplify the behavior to be controlled with a few adjustable parameters and so on.
For example, you store the positions of your enemy and player as a static integer in your main class. This is not OO. Move the positions to the entity class where you can implement it in whatever manner you wish.
Don't just throw an exception for no reason
Your update(...) method throws a SlickException even though it's never needed.
Be careful about encapsulation
This is something a lot of beginners do: Just grab some parameters, put them in a class as private (or maybe even public) and generate getters- and setters for them. This is not encapsulation. This is almost as bad as making them public in the first place.
But why don't we just make everything public?
We don't want anyone (or even ourselves) to rely on some parameters that just happen to be there because of some very specific implementation of something we might want to change later. Don't just put all possible values out there to be changed, the sense of encapsulation is to be independent from what kind of implementation we end up using and to protect the usability of our code by guarding what can be set/changed.
Performance does matter
This is one of the aspects you should watch out for, for any kind of software, but you can often most drastically see the consequences in games. Performance is important! And by that, I don't mean that you have to watch out for every single detail, but just keep an overview in mind on how to improve and fasten up your code, especially with frequently called methods such as update(..) and render(..) in Slick2D.
Update
As a solution to another problem discussed in the comments:
public class Enemy {
private int startX, startY, width, height;
public Shape rect = new Rectangle(startX, startY, width, height);
// plus getters and setters
}
width and height can only be 0 as they are never assigned an integers have the value 0 per default, so the enemy rectangle hitbox does have 0 width and will never trigger.
Try something like:
public class Enemy {
private int startX, startY, width = 50, height = 70;
public Shape rect = new Rectangle(startX, startY, width, height);
// plus getters and setters
}
This should work, but you should probably move all these attributes to the enemy class and put them in the constructor.
I am currently working on a space invaders style game but I have run into a bit of trouble with multiple instances of bullets. At the moment I can only fire one. I have been trying to get it to work with an Array List but I just can't seem to get it to work. The closest I got I got it to working was, it fired multiple bullets but they all spawned from the same location as in the bullets didn't spawn in relation to the ships position. The game also crashed when I removed an object after it exceeded it's boundary. Can anyone help me to see where I am going wrong. Here is some code that I have so far the parts commented out are my attempts at getting the array list to work
import java.util.ArrayList;
import org.newdawn.slick.Input;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.GameContainer;
public class Player extends Entity
{
private int speed = 5;
private ArrayList<Bullet> bulletList;
private boolean firing;
private Bullet bullet;
public Player()
{
bullet = new Bullet();
//bulletList = new ArrayList<Bullet>();
this.setImage("ship");
this.setPosition(350,450);
this.setDimenseions(100, 100);
this.createRectangle();
}
#Override
public void entityLogic(GameContainer gc, int deltaTime)
{
Input input = gc.getInput();
if(input.isKeyDown(Input.KEY_A))
{
this.x -= speed;
}
if(input.isKeyDown(Input.KEY_D))
{
this.x += speed;
}
if(input.isKeyDown(Input.KEY_W))
{
this.y -= speed;
}
if(input.isKeyDown(Input.KEY_S))
{
this.y += speed;
}
if(input.isKeyPressed(Input.KEY_SPACE))
{
firing = true;
bullet.x = this.getX()+40;
//BulletList.add(new Bullet());
}
if(firing)
{
/*Carries out the logic for the bullet*/
//for(Bullet b : bulletList)
//{
//b.entityLogic(gc, deltaTime);
//}
//Moves the bullet negativly along the y axis
bullet.entityLogic(gc, deltaTime);
}
}
#Override
public void entityRendering(Graphics g)
{
g.drawImage(this.getImage(), this.getX(), this.getY());
if(firing)
{
/*Draws each bullet object in the list*/
//for(Bullet b : bulletList)
//{
//b.entityRendering(g);
//}
bullet.entityRendering(g);
}
}
}
First of all forget about your Bullet bullet instance variable. You don't need it, the list is enough.
Another thing is that you could use a LinkedList instead that an ArrayList because you don't need random access and you have to add and remove items frequently, when you iterate over bullets to check for collision use a ListIterator<T> and remove them on the fly.
Finally it should be something like:
List<Bullet> bullets = new ArrayList<Bullet>();
public void entityLogic(GameContainer gc, int deltaTime) {
// since this method is called many times you should shoot a bullet just every X msec
if (spacebar pressed) {
// you spawn a new bullet according to player position
Bullet bullet = new Bullet(player.x,player.y);
// you add it to the list
bullets.add(bullet);
}
// destroy bullets which are outside the viewport
for (int i = 0; i < bullets.size(); ++i) {
Bullet bullet = bullets.get(i);
if (bullet.isOutsideBounds()) {
bullets.remove(i);
i--;
}
}
public void entityRendering(Graphics g) {
for (Bullet bullet : bullets)
bullets.entityRenering(g);
}
}
This is just to give you the basic idea.
I don't know slick2d and how it manages the rendering and logic threads, if they are two different threads then you should use a syncronized list, eg:
List<Bullet> bullets = Collections.synchronizedList(new ArrayList<Bullet>());
The city in my game is randomly generated but is a graph of roads and intersections that can only form rectangles:
As can be seen, my terrain is pretty empty. What I want to do is find each empty rectangle and store in in a list of rectangles, forming Lots.
As you can see in this illustration, I filled in 3 'lots' and in 1 I showed the 3 rectangles it is made of.
My data structures are:
package com.jkgames.gta;
import android.graphics.Bitmap;
import android.graphics.RectF;
public class Intersection extends Entity
{
Road topRoad;
Road leftRoad;
Road bottomRoad;
Road rightRoad;
Bitmap image;
public Bitmap getImage()
{
return image;
}
public void setImage(Bitmap image)
{
this.image = image;
}
public Intersection(RectF rect, Bitmap image)
{
setRect(rect);
setImage(image);
}
public Road getTopRoad()
{
return topRoad;
}
public void setTopRoad(Road topRoad)
{
this.topRoad = topRoad;
}
public Road getLeftRoad()
{
return leftRoad;
}
public void setLeftRoad(Road leftRoad)
{
this.leftRoad = leftRoad;
}
public Road getBottomRoad()
{
return bottomRoad;
}
public void setBottomRoad(Road bottomRoad)
{
this.bottomRoad = bottomRoad;
}
public Road getRightRoad()
{
return rightRoad;
}
public void setRightRoad(Road rightRoad)
{
this.rightRoad = rightRoad;
}
#Override
public void draw(GraphicsContext c)
{
c.drawRotatedScaledBitmap(image, getCenterX(), getCenterY(),
getWidth(), getHeight(), getAngle());
}
}
public class Road extends Entity
{
private Bitmap image = null;
private Intersection startIntersection;
private Intersection endIntersection;
private boolean topBottom;
public Road(RectF rect, Intersection start, Intersection end,
Bitmap image, boolean topBottom)
{
setRect(rect);
setStartIntersection(start);
setEndIntersection(end);
setImage(image);
setTopBottom(topBottom);
}
#Override
public void draw(GraphicsContext c)
{
//Rect clipRect = c.getCanvas().getClipBounds();
//c.getCanvas().clipRect(getRect());
float sizeW;
float sizeH;
if(isTopBottom())
{
sizeW = getWidth();
sizeH = (sizeW / image.getWidth()) * image.getHeight();
}
else
{
sizeW = getHeight();
sizeH = (sizeW / image.getWidth()) * image.getHeight();
}
int numTiles = isTopBottom() ? (int)Math.ceil(getHeight() / sizeH) :
(int)Math.ceil(getWidth() / sizeW);
for(int i = 0; i < numTiles; ++i)
{
if(isTopBottom())
{
c.drawRotatedScaledBitmap(
image,
getRect().left + (sizeW / 2.0f),
(getRect().top + (sizeH / 2.0f)) + (sizeH * i),
sizeW, sizeH, 0.0f);
}
else
{
c.drawRotatedScaledBitmap(
image,
getRect().left + (sizeH / 2.0f) + (sizeH * i),
getRect().top + (sizeH / 2.0f),
sizeW, sizeH, (float)Math.PI / 2.0f);
}
}
// c.getCanvas().clipRect(clipRect);
}
public Bitmap getImage()
{
return image;
}
public void setImage(Bitmap image)
{
this.image = image;
}
public Intersection getStartIntersection()
{
return startIntersection;
}
public void setStartIntersection(Intersection startIntersection)
{
this.startIntersection = startIntersection;
}
public Intersection getEndIntersection()
{
return endIntersection;
}
public void setEndIntersection(Intersection endIntersection)
{
this.endIntersection = endIntersection;
}
public boolean isTopBottom()
{
return topBottom;
}
public void setTopBottom(boolean topBottom)
{
this.topBottom = topBottom;
}
}
The city is a list of roads and intersections.
Is there some sort of algorithm that could generate these lots and their rectangles?
Thanks
The easiest method that comes to my mind is to use a flood-fill algorithm to build up your list of regions. So basically
foreach square:
if the square isn't part of a region:
create a new empty region list
add the square to it
recursivly add all neighboring squares to the region
The end result will be that you'll have a list of regions which you can then do whatever you want with (look and see if any of the contained squares have buildings on, color in for the user, etc..).
Note: to determine whether a square is part of a region or not, I'd add a marked flag or something to the square data structure, that way when you start, you go through and clear all those flags, then as you add a square to a region you set that flag, and when you want to check to see if a square is in a region, all you need to do is check to see if that flag is set or not. That way you end up with a linear time algorithm to construct your list of regions.
As Markus pointed out in the comments here, this "flag" could be in fact a pointer/reference to a Lot object that holds the list of your squares, which would probably be convenient to have handy anyways.
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++) {
if (x > 0 && squares[y][x].isConnectedTo(squares[y][x-1]) {
// Connected from the left
squares[y][x-1].getLot().addSquare(squares[y][x]);
if (y > 0 && squares[y][x].isConnectedTo(squares[y-1][x]) {
// Connected from both the left and above
squares[y-1][x].getLot().mergeWith(squares[y][x].getLot());
}
}
else if (y > 0 && squares[y][x].isConnectedTo(squares[y-1][x]) {
// Connected from above
squares[y-1][x].getLot().addSquare(squares[y][x]);
}
else {
// Not connected from either
createNewLot().addSquare(squares[y][x]);
}
}
Lot.addSquare(…) adds a square to the lot, and calls setLot(…) on the square.
Lot.mergeWith(…) merges two lots, and reassigns the squares assigned to them, if they are not the same lot.
Square.isConnectedTo(…) checks if they are neighbors, and that there is no road in between.
You could optimize this by using the Disjoint-set data structure