Fixed timestep and gamespeed - java

this is my first game and I'm not that experienced of a programmer but I've researched a lot and I've worked on this game every day for the last couple of weeks. I research different things on this website every day and I find your posts here tremendously helpful :)
I have a question regarding fixed timestep loops, can't wrap my head around why changing the time to wait between updates affects the speed of which my entire game moves. Maybe there's something I'm missing or something I don't understand yet
My loop looks like this:
private void gameLoop(){
final double updateWaitTime = 1000000000/50;
double nextUpdateTime = System.nanoTime();
while(running) {
double now = System.nanoTime();
while( now > nextUpdateTime) {
updateGame(now);
nextUpdateTime += updateWaitTime;
}
double interpolation = (now+updateWaitTime-nextUpdateTime)/updateWaitTime;
drawGame(interpolation);
}
}
If I decrease the value of updateWaitTime, my game moves much faster because it is getting updated so much more.
The methods that execute my movement looks like this, they both get the current time with getNanoSecond() which holds the same value that the gameLoop sets "now" as.
protected void travel(){
if(moveShotTime <= c.getNanoSecond()){
setX(getX()+dx);
setY(getY()+dy);
moveShotTime = c.getNanoSecond()+bulletMoveDelay;
}
}
//[0] = degree. [1] = distance. [2] = movementspeed
public void move(){
if(moves.isEmpty() == false){
ArrayList<double[]> movementDirection = moves.get(0);
if(movementDirection.isEmpty() == false){
double[] oneMove = movementDirection.get(0);
if(getNextMoveTime() <= c.getNanoSecond()){
else if(oneMove[1] > distanceMoved){
double radian = (oneMove[0]/360)*2*Math.PI;
double dx = round((Math.cos(radian)*oneMove[2]), 9);
double dy = round((Math.sin(radian)*oneMove[2]), 9);
double dz;
if(dx<0){
dz = round(dx/(Math.cos(radian)), 5);
}
else if(dx==0){
dz = dy;
}
else if(dy==0){
dz = dx;
}
else{
dz = round((dx/(Math.cos(radian))), 5);
}
setX(getX()+dx);
setY(getY()+dy);
if(dz<0){
distanceMoved = distanceMoved-dz;
}
else{
distanceMoved = distanceMoved+dz;
}
movedX = movedX + dx;
movedY = movedY + dy;
}
else{
movementDirection.remove(0);
distanceMoved = 0;
}
}
}
else{
setPreviousX(getX()-movedX);
setPreviousY(getY()-movedY);
moves.remove(0);
}
}
else{
}
}
So what I'm wondering is why changing the updateWaitTime affects the speed of everything. Since I'm using timestamps as a reference for when to execute the movement again, in my mind it shouldn't make a difference how often the game is updated as long as it's more often than the timesteps inside of the game. I'm new to this and I'm surely missing something here. I would also like to ask what a common update-time for games are on PC and android? If I can't figure this out I'm gonna have to set an update-time that I can't change to work with from here on (since i would have to adjust everything in the game).
Thanks in advance and thanks for all the great info on this website!! :)

Related

Check if a player can place a block at a said location

I am creating a custom anti-cheat. However, I have come to a point where I am quite stumped. I am attempting to detect whether a player can place a block at a said location, but it is becoming increasingly convoluted as I try to make it more reliable for non-cheating players. Currently, I am incorporating a raycast algorithm (usingAxisAllignedBB) whenever a player interacts with a block (PlayerInteractEvent) to see if the player is actually looking at the Block and BlockFace the event says they were. The problem, I believe, is the player's direction is only updated 20 times a second where their frame rate might be much higher. This often causes (about once every 15 or so block places from my testing) the PlayerInteractEvent to be incorrectly canceled.
Raycast Algorithm for finding Block looked at
public static Block getTargetBlock(Location location, Vector direction, double rangeSquared, int maxTrials, TargetMethod targetMethod) {
Location loc = location.clone();
Vector dir = direction.normalize();
final double directionX = direction.getX();
final double directionY = direction.getY();
final double directionZ = direction.getZ();
Block block = loc.getBlock();
for (int i = 0; i <= maxTrials; i++) {
final double locX = loc.getX();
final double locY = loc.getY();
final double locZ = loc.getZ();
double wholeMoreX = wholeMore(locX,directionX);
double moreX = Math.abs(wholeMoreX /directionX);
double wholeMoreY = wholeMore(locY,directionY);
double moreY = Math.abs(wholeMoreY /directionY);
double wholeMoreZ = wholeMore(locZ,directionZ);
double moreZ = Math.abs(wholeMoreZ /directionZ);
if(moreX < moreY && moreX < moreZ){
if(directionX > 0)
block = block.getRelative(BlockFace.EAST);
else {
block = block.getRelative(BlockFace.WEST);
}
}
else if(moreY < moreX && moreY < moreZ){
if(directionY > 0){
block = block.getRelative(BlockFace.UP);
}
else{
block = block.getRelative(BlockFace.DOWN);
}
}
else{
if(directionZ > 0){
block = block.getRelative(BlockFace.SOUTH);
}
else{
block = block.getRelative(BlockFace.NORTH);
}
}
final double scalar = Math.min(Math.min(moreX,moreY),moreZ);
Vector addAmount = dir.clone().multiply(scalar);
loc.add(addAmount);
if(loc.distanceSquared(location) > rangeSquared)
return null;
AxisAlignedBB boundry = getBoundry(block,targetMethod);
if(boundry != null)
if(blockFaceCollide(location,direction,boundry) != null)
return block;
}
return null;
}
However, I doubt this is the issue. From my testing, it works perfectly fine. Thus, I think I must rely on alternative methods. Here are some ideas, but I am not quite sure they are satisfying.
Idea: Near Blocks
I have thought about seeing if the block placed is within a 1 block radius (or possibly shorter if I am looking at closest distance to block from ray) of the block found from the raycast, but this offers too many problems. If a player is moving their cursor from a barrier to a further out area, a false positive for cheating would be fired. On the other hand, players could still build in a fully enclosed area if they had block pillars North, East, South, West but not North-West, North-East, etc.
Idea: A* Path finding Algorithm
If I made points on the ray in the raycast have 0 G-Cost, with G-Cost increasing with distance from the ray and the H-Cost being the closest distance to the targeting block, I feel this could solve this dilemma. I could set a max G-Cost threshold before the PlayerInteractEvent is canceled. The problem, however, is incorporating A* with various AxisAllignedBB of blocks seems difficult. I might be able to create a grid which consists of 100x100x100 points per block, but I am not sure this would be efficient nor best practice.
Idea: See if the player can see the block
This would be highly effective, but I am not sure whether it would be realistic. For this, each time a player places a block I would need to detect which blocks would completely overlap other blocks in the player's interact radius. Taking all the final non-overlapped blocks, I could see if the interacted block contains these. If not, the interaction would be canceled. This seems like it might take a performance hit, and I could see how there could also be some false positives for cheating.
I'd suggest to create a method that informs if Player and block intersects.
Sample Code
public static final double ONE_UNIT = 1.0;
public static final double ZERO_UNIT = 0.0;
public static Location getPlayerBlockIntersection(Player player, Block target) {
if (player == null || target == null) {
return null;
}
double minX = target.getX();
double minY = target.getY();
double minZ = target.getZ();
double maxX = minX + ONE_UNIT;
double maxY = minY + ONE_UNIT;
double maxZ = minZ + ONE_UNIT;
Location origin = player.getEyeLocation();
double originX = origin.getX();
double originY = origin.getY();
double originZ = origin.getZ();
Vector dir = origin.getDirection();
double dirX = dir.getX();
double dirY = dir.getY();
double dirZ = dir.getZ();
double divX = ONE_UNIT / dirX;
double divY = ONE_UNIT / dirY;
double divZ = ONE_UNIT / dirZ;
double t0 = ZERO_UNIT;
double t1 = Double.MAX_VALUE;
double imin, imax, iymin, iymax, izmin, izmax;
if (dirX >= ZERO_UNIT) {
imin = (minX - originX) * divX;
imax = (maxX - originX) * divX;
} else {
imin = (maxX - originX) * divX;
imax = (minX - originX) * divX;
}
if (dirY >= ZERO_UNIT) {
iymin = (minY - originY) * divY;
iymax = (maxY - originY) * divY;
} else {
iymin = (maxY - originY) * divY;
iymax = (minY - originY) * divY;
}
if ((imin > iymax) || (iymin > imax)) {
return null;
}
if (iymin > imin) {
imin = iymin;
}
if (iymax < imax) {
imax = iymax;
}
if (dirZ >= ZERO_UNIT) {
izmin = (minZ - originZ) * divZ;
izmax = (maxZ - originZ) * divZ;
} else {
izmin = (maxZ - originZ) * divZ;
izmax = (minZ - originZ) * divZ;
}
if ((imin > izmax) || (izmin > imax)) {
return null;
}
if (izmin > imin) {
imin = izmin;
}
if (izmax < imax) {
imax = izmax;
}
if ((imin >= t1) || (imax <= t0)) {
return null;
}
// check this baby and see if both objects represent an intersection:
Location intersection = origin.add(dir.multiply(imin));
return intersection;
}
I'm not sure if this works. But I thought about using the BlockPlaceEvent and check when the Block is placed if the Player is looking at that block.
#EventHandler
public void blockplace(BlockPlaceEvent event){
Player p = event.getPlayer();
int x = p.getLocation().getDirection().getBlockX();
int y = p.getLocation().getDirection().getBlockY();
int z = p.getLocation().getDirection().getBlockZ();
Location lookingLoc = new Location(p.getWorld(),x,y,z);
if (!event.getBlockPlaced().getLocation().equals(lookingLoc)){
//flag player...
}
}
Feel free to leave recommendations.
I read the question a couple times to be sure. If I understand the premise,
you wish to verify when an interaction occurs that the player is
looking at the block being interacted with. I take it that you want to prevent "auto-build" mods or
the like that may fake such events.
The validation should be straightforward using Player.getTargetBlock().
If the block returned by getTargetBlock() is the same as that reported
by PlayerInteractEvent you should be reasonably confident that the player is
looking at the block.

Android Game Logic - Obsticles

I have been working on android apps for a long time but now I have decided to create a game aside with my pre-calculus final. I have completed the whole code and it works perfectly except one tiny issue. First of the game is based on flying pig(my classmate's face) avoiding top and bottom osticle. I developed an algorithm so that the obsticles are evenly spaced and based on random selection placed either as the top or bottom of the screen but never both at the same time!. The algorithm that needs improvement is in the 3rd code segment!
This is the screenshot of the problem: screenshot here
(My account is new so stackoverflow wont let me to share photos directly)
This is the class that calls updates for all dynamic objects (ship = pig, bacon = bonus item, BM = BarrierManager class's update() which updates the obsticles)
//this will update the resources
void Update(float dt) {
ship.update(dt);
//bumbing
if (!ship.death) {
background.update(dt);
**BM.update(dt);**
for (int i = 0; i % 5 == 0; i++) {
bacon.update(dt, BM.position);
}
}
ArrayList<Point> bacon_point = new ArrayList<Point>(bacon.getArray());
if (ship.bump(bacon_point.get(0), bacon_point.get(1), bacon_point.get(2), bacon_point.get(3))) {
bacon.setX(-200);
bacon.setY(-200);
Message msg = BM.game_panel.game.handler.obtainMessage();
msg.what = 0;
BM.game_panel.game.handler.sendMessage(msg);
}
for (int i = 0; i < BM.TopWalls.size(); i++) {
ArrayList<Point> temp = new ArrayList<Point>(BM.TopWalls.get(i).getArray());
//after we have accest the TopWalls arraylist we can call bump that check TopWalls object's points position with the pig's points
ArrayList<Point> temp2 = new ArrayList<Point>(BM.BottomWalls.get(i).getArray());
//after we have accest the TopWalls arraylist we can call bump that check BottomWalls object's points position with the pig's points
if ((ship.bump(temp.get(0), temp.get(1), temp.get(2), temp.get(3))) || (ship.bump(temp2.get(0), temp2.get(1), temp2.get(2), temp2.get(3))) || ship.death) {
ship.death = true;
game.onStop();
while(f==0) {
MediaPlayer mp = MediaPlayer.create(game, R.raw.explosion_fart);
mp.start();
f++;
}
f++;
Message msg = BM.game_panel.game.handler.obtainMessage();
msg.what = 1;
BM.game_panel.game.handler.sendMessage(msg);
i = BM.TopWalls.size()-1;
if(f == 8){
thread.setRunning(false);
}
}
}
}
In the BarrierManager I have created this update method which takes float dt = MainTheards general time for the game.
TopWalls is ArrayList this ArrayList is composed of top obsticles. Bottom walls is the same but BottomWalls.
//zreb decides if it should create TopWalls or BottomWalls object. This parameter is later transfered to the Barier.update method where I work with it
public void update(float dt){
for (int i=0;i<Num+1; i++) {
int zreb = new Random().nextInt(2);
//{if} to make the spacing bigger
if (i % 5 == 0){
**TopWalls.get(i).update(dt, true, zreb);
BottomWalls.get(i).update(dt, false, zreb);**
if(zreb == 0){
position.set(TopWalls.get(i).getX(), TopWalls.get(i).getY());
}
else{
position.set(BottomWalls.get(i).getX(),BottomWalls.get(i).getY());
}
}
}
}
Now this algoritm in the Barrier.class is where the magic went wrong. This update method takes the float dt mentioned earlier, a boolean variable for determining if the obsticle we work with at that instance is the Top or Bottom, and the zreb random int that determines if the top or bottom obsticle is going to be shown.
//problem! needs to be discussed
public void update(float dt, boolean b, int zreb) {
//checking if the barrier is still there
if (x<-bitmap.getWidth()){
//'b'is passed from the Barriermanager - 'update' method, determining if we have to use monkey-true or farmer-false
int raz = 200;
int vyska = BM.dpos;
//'zreb' helps me to randomly determine if monkey or ballard is going to appear
//here it determines if we are going to have Top or Bottom obsticle in the game
if(zreb == 1) {
vyska = BM.dpos - raz;
}
else {
vyska = BM.dpos + raz;
}
//koniec tohto trienedia
if (b)
{
//setting the y value for the top wall
y = vyska - BM.dl/2 - bitmap.getHeight()/2;
}
else{
//setting the y value for bottom wall
y = vyska + BM.dl/2 + bitmap.getHeight()/2;
}
//setting x-value
x = (int) (x +bitmap.getWidth()*(BM.TopWalls.size()-1));
}
x = (int) (x - BM.game_panel.ShipSpeed*dt);
}
Do you have any idea why this "one-or-the-other" condition is not working properly?
This would help me lot because this error made me deactivate the app from the store.

Unable to use my method with Slick library

So I made a java game with jumping some time ago and I used this method for all the moving:
double height = 0, speed = 4;
public static final double gravity = 9.81;
double x = 25;
int a;
int y = (int) (500-(height*100));
boolean left = false, right = false, up = false;
public void the_jump() {
long previous = 0, start = 0;
while(true){
start = System.nanoTime();
if(previous != 0 && up){
double delta = start - previous;
height = (height + (delta/1000000000) * speed);
speed -= (delta/1000000000) * gravity;
y = (int) (500-(height * 100));
}
if(left){
x-= 3;
}
if(right){
x+= 3;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(height < 0){
height = 0;
speed = 4;
up = false;
}
previous = start;
}
}
Now It was okay when I did it all with just JComponents and such, but now when I want to implement it in a Slick enviroment, it fails.
The problem is in the while(true){} loop. If I change it against for(int i = 0; i < 1; i++) loop, then moving left and right will work. But this will not work for the jumping. I could increase the i < 1 to i < 5 and then the jump will work, but at the cost of a lot of performance.
So how would people implement this in slick? Right now I am calling the the_jump(); out in my public void update(GameContainer gc, int t) throws SlickException method, and if I use the while loop, the game will crash.
Slick already loop on update(GameContainer gc, int delta), you have to put all the code located in your while loop into the update method.
Moreover, you get the delta time between two update as parameter, and so not have to calculate it.
Feel free to ask me more question ;)
Off Topic, do you know if Slick2d is still maintain ? I switch to libGDX a few month ago, and I really advice you to test it, it's soooo fun :)

The paddle of pong keeps shaking without staying at one position

Please look at the following structure of my pong game.
gameLoop(); method
//Only run this in another Thread!
private void gameLoop()
{
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while (running)
{
double now = System.nanoTime();
int updateCount = 0;
if (!paused)
{
//Do as many game updates as we need to, potentially playing catchup.
while( now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER )
{
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if ( now - lastUpdateTime > TIME_BETWEEN_UPDATES)
{
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES) );
//float interpolation = 1.0f;
drawGame(interpolation);
lastRenderTime = now;
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while ( now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES)
{
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
try {Thread.sleep(1);} catch(Exception e) {}
now = System.nanoTime();
}
}
}
}
updateGame(); method
if(p1_up){
if(player.equals("p1")){
p1.moveUp();
}
else
{
p2.moveUp();
}
}
else if(p1_down){
if(player.equals("p1")){
p1.moveDown();
}
else
{
p2.moveDown();
}
}
moveUp(); moveDown(); method of paddle
public void moveUp(){
last_y = y;
last_x = x;
y -= 50.0;
}
public void moveDown(){
last_y = y;
last_x = x;
y += 50.0;
}
drawGame(interpolation); method
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=0;i<balls.size();i++){
paintBall(g, balls.get(i));
}
drawPaddle(g, p1);
drawPaddle(g, p2);
}
public void drawPaddle(Graphics g, Paddle p){
paddle_drawX = (int)((p.x - p.last_x)*interpolation + p.last_x);
paddle_drawY = (int)((p.y - p.last_y)*interpolation + p.last_y);
g.drawRect(paddle_drawX, paddle_drawY, 10, 50);
}
I am a beginner in game programming so i don't have a good idea about game loops. I found the above fixed time-step game loop in the internet and used it as the game loop for my game. The loop makes the ball move smoothly but the paddle isn't staying at one place when moved. When I move my paddle by pressing one down key stroke then the paddle keeps shaking
without stopping in one spot. The y coordinates of the paddle keeps changing like
33, 45, 20, 59, 34, 59, 34, 59, 33, 59, 34, 58
I know the problem is in interpolation value as it keeps changing value that will change the y coordinate of paddle in render. I have been thinking about this for a while and i don't know how to make the game loop work for any movements so i have come here for some help. I appreciate any suggestion/help!
Here is my full Paddle class.
public class Paddle
{
float x;
float y;
float last_y;
float last_x;
public Paddle(int x, int y)
{
this.x = x;
this.y = y;
this.last_x = x;
this.last_y = y;
}
public void setNewX(int d){
last_y = y;
last_x = x;
x = d;
}
public void setNewY(int d){
last_y = y;
last_x = x;
y = d;
}
public void moveUp(){
last_y = y;
last_x = x;
y -= 50.0;
}
public void moveDown(){
last_y = y;
last_x = x;
y += 50.0;
}
}
and i initiate the paddle position in the main class through global variable.
public Paddle p1 = new Paddle(10, 10);
public Paddle p2 = new Paddle(950, 10);
I have following event listeners for handling key strokes.
Action handle_up_action = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_up = true;
}
};
Action handle_up_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_up = false;
}
};
Action handle_down_action = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_down = true;
}
};
Action handle_down_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_down = false;
}
};
What are you trying to achieve with interpolation? From my understanding, it represents the percentage of time elapsed between previous previous and next "update time".
So it should progress continuously from 0 to 1 each 33.3 ms.
I don't know how you use this interpolation variable in the paintBall method, but for the paddles, it will draw your paddle at a "pseudo random position" between p.x;p.y and p.last_x;p.last_y (depending on the time between the two updateGame()).
In order to correct this, from your loop logic, you should understand that every game entity (balls, paddles, ...) must have two states (the positions):
- the logical state, which is updated only each TIME_BETWEEN_UPDATES
- the visual state, which can be updated anytime, at each render.
It is the same as if you have a set of points (which represent the logical states) and you want to interpolate anywhere between this points (reprensenting the visual state).
Your code is like this.
First solution
The simplest way to correct the paddle shaking, is to avoid the interpolation and use:
public void drawPaddle(Graphics g, Paddle p){
paddle_drawX = (int)p.x;
paddle_drawY = (int)p.y;
g.drawRect(paddle_drawX, paddle_drawY, 10, 50);
}
But your movement will look like this (visual position will be changed only each TIME_BETWEEN_UPDATES)
Second solution
You want p.x;p.y to be the logical position, but the visual position should be interpolated between p.last_x;p.last_y and the logical position if the rendering is done between the input processing and the next updateGame(): you must reset p.last_x;p.last_y when updateGame() is called. To achieve this, call the paddles' updateMovement() method inside updateGame().
public void updateMovement(){
last_y = y;
last_x = x;
}
You can have other solutions, such as to use a speed variable or a movement function, in order to have a smooth movement, accelerations, and so on. It is mainly a generalisation of second solution. It requires bigger changes, but it is more flexible and powerful. To achieve this, you may want to store in paddles the last "update position", and all movement-related variables, such as movement start date. Add a method to retrieve the "visual position" that can be called with any date between two updates, and a method to update the "logical position" called each updateGame().

Point Inside Circle Collision Response: How do you keep the Point inside of the circle?

I have given a diagram of my current small problem that I need help with. My main purpose is to keep the point from going outside the circle. Nothing else.
The center of the circle is positioned at (x, y).
I only solved a little bit of the problem, and that is the collision detection part of my problem, as given below:
public void bound(Point p, Circle c){
double distance = Math.hypot(p.x - c.x, p.y - c.y);
if (distance >= c.radius){
//Clueless from here on out.
}
}
The part where I left a comment is the spot I couldn't figure anything out. I did tried to set the point's velocityX and velocityY to 0, but I realized the point will just stay put whenever it touches the circle.
So, I'm sort of stuck.
I have resolved this issue.
public void reflect(Hole h){
//R = -2*(V dot N)*N + V
//N is normalized.
double nx = (this.position[0]+this.diameter/2) - (h.x+16);
double ny = (this.position[1]+this.diameter/2) - (h.y+16);
double nd = Math.hypot(nx, ny);
if (nd == 0)
nd = 1;
nx /= nd;
ny /= nd;
double dotProduct = this.speed[0]*nx+this.speed[1]*ny;
this.speed[0] += (float)(-2*dotProduct*nx);
this.speed[1] += (float)(-2*dotProduct*ny);
}
public void reflectResponse() {
for (int i = 0; i <= 1; i++) {
position[i] -= speed[i];
speed[i] *= 0.992f;
}
}
I tried Oli Charlesworth's method from the comments, but it made things more... "complicated" than I expected. Someone else mentioned I used a completely 100%, vector-based algorithm, since I'm relying a lot on vector-based movements.
TIPS TO THOSE WHO DO READ THIS:
If you're working on object movements and collisions with vectors, seek vector-based algorithms.
If you're working with angles (either degrees or radians), use Oli Charlesworth's method.

Categories