:D
I'm currently making an RPG, made the combat system, if a player attack makes contact with the enemy it deals damage, now what I want to do is add critical strike into the mix and blocking.
How it should work? well first it will roll the chances of the monster blocking based on his blocking chance, if it blocks the incoming damage gets reduced to zero, if it doesnt it rolls the chance of critical strike based on the players critical strike chance, if its critical it will deal x bonus amount of damage based on the players critical strike multiplier.
Now what I want to know is how to calculate the percentage chance, I've seen several posts but they usually turn the percentage into a whole number, and probably my players will start with low rolls as 1.7% or 3.9%, but not 1-2-3-5, flat percentages. Anyone got suggestions on how to make it?
so far the code goes like this:
public class Player{
private double criticalStrikeChance = 0.009; <--- thats 0.9% chance.
private double criticalStrikeMultiplier = 1.2; <--- thats 120% moar damage
public double getCritStrk(){
return criticalStrikeChance;
}
}
public class Monster(){
private double blockingChance = 0.3; <--- thats 30%
private double blockingReduction = 0.75; <--- thats 75% reduced damage when blocking
}
public class Game(){
public void checkIfDamaged(){
if(intersects){
// blockroll should be done here based on the monster chance
if(blockRoll >= minimum he had to roll){
//means its successfull
monster.getHit(0); //PEANUT DAMAGE ACHIEVED GREAT SUCCESS
}else{
//Critical strike chance should be rolled here based on player
//chance
if(critstrike successful){
incdamage + (incdamage * player.criticalStrikeMultiplier;
monster.getHit(incdamage);
}
}else{//Crit didnt roll with cinnamon
monster.getHit(player.getDamage);
}
}
}
}
Ok so that's pretty much it as pseudo-code because my code looks way different but thats simple and should give you guys an idea on how it should work, so please help me senpais! I SHALL GIVE YOU CHOCO COOKIES + a nice shield with 100% block rate :D to whoever halps me!
If you are just looking to roll a random percentage, you can use the Random class in java.
Random rand = new Random();
Double pickedNumber = rand.nextDouble();
Running that, will result in pickedNumber being some double between 0 and 1. For example:
0.3650998187710377
Then check if that percentage is less than whatever your block/crit chance is. For example:
if(pickedNumber < blockChange)
//doBlock();
A full example, for a test case could be something like:
private static Random rand = new Random();
public static void main(String[] args) {
double blockChance = .5; // 50% chance to block the attack
Double pickedNumber = rand.nextDouble(); // Roll to see if we block the attack
System.out.println(pickedNumber); // output roll for debug purposes
if(pickedNumber < blockChance){ // if the attack was blocked
System.out.println("Blocked"); // do block logic
}else{ // if the attack wasn't blocked
System.out.println("Damaged"); // do damage logic
}
}
Which gave me the output:
0.2768592334674802
Blocked
And:
0.8762124334674802
Damaged
Another approach:
To get 0.75:
if (Math.random() < 0.75) {
//do this with probability 0.75
}
Related
I am just looking to confirm that this code would be correct for what I am looking for. Basically, I would like when called, this function to roll a number out of a certain rarity. The rarities right now are 15% chance, 20% chance, and a 65% common chance. However, after rereading my code, it seems to be that the 20% chance actually is a lower chance than the 15% chance which would not be ideal. Could someone check this for me? Thanks!
public void roll() {
float rarity = random.nextFloat();
if(rarity <= 0.15f) {
// Roll Legendary Item
} else if(rarity <= 0.35) {
// Roll Rare Item
} else {
// Roll Common Item
}
}
It should be
else if(rarity <= 0.35f)
The way your code is written, it is currently 15%-5%-80%
I am creating a device where you can do video game bike racing by putting your bicycle on a trainer and hooking it up to your tablet/phone, which will count the pulses from a reed switch or hall effect sensor and calculate your speed, distance, etc in the same manner as a regular bike computer, and use that to move your avatar in the game world. It's written in Java with libGDX.
I'm stuck trying to get the digital bike to coast to a stop. If you are going a given speed, such that the time between pulses is normally 100ms, then if we check the time delta and it's been 200ms since the last click, we know you can't be going more than half of your former speed, and we should adjust down accordingly every time we update your speed, eventually passing some threshold where we decide you've effectively stopped.
I want the speed to decay along a roughly logarithmic curve so that hopefully I can approximate the speed envelope that your bike would have out on pavement. I also need to be smart about estimating the distance you've traveled since the last click, so that your distance doesn't jump ahead if we suddenly get a click.
How can I accomplish getting the bike to coast to a stop, and how should I go about positioning the bike in the game world with the uncertainty of how far we have to go until the next click? I have scoured the Internet looking for examples of code for a bicycle computer, and haven't found any yet, let alone any that have the added restriction that they need to be able to render their current position in the game world.
Here's the code:
The click function runs every time we get another pulse from the bike sensor:
public void click() {
currentTime = System.currentTimeMillis();
int delta = (int) (currentTime - lastClick);
// If we have less than N samples, just add it to the list.
// Otherwise pop one off and fill it in with the new value.
if (samples.size() == SAMPLE_RESOLUTION) {
samples.remove(0);
}
samples.add(delta);
clicks += 1;
lastClick = currentTime;
}
And the averageSamples function averages the last N samples to smooth out the speed. It's just a simple average right now, but later I intend on making it weighted such that new data is weighted more than old data.
public double averageSamples() {
Integer sum = 0;
if (!samples.isEmpty()) {
for (Integer sample : samples) {
sum += sample;
}
return wheelCircumference / (sum.doubleValue() / samples.size());
}
return sum.doubleValue();
}
And finally, the update function runs every frame of the game, so about once every 60th of a second. It's supposed to calculate your speed and distance, guessing how far you've gone since the last click based on the amount of time that's passed since then:
public void update() {
double newSpeed;
currentTime = System.currentTimeMillis();
int delta = (int) (currentTime - lastClick);
// The below line needs to adjust your speed downward if it's been too long since the last click. We're hoping for a smooth curve on the way to coasting to a stop.
newSpeed = averageSamples();
elapsedTime = currentTime - startTime;
instSpeed = newSpeed;
avgSpeed = (avgSpeed + instSpeed) / 2;
maxSpeed = Math.max(newSpeed,instSpeed);
/* This line needs to guess how far you've gone since the last click. Right now I'm using this value directly to draw the bike at a certain place in the game world, so we need to do this in a way that if we suddenly get a click, you don't end up jumping forward. */
distance = (long) (clicks * wheelCircumference);
}
So I have a problem I've been wracking my brain over for about a week now. The situation is:
Consider a checkout line at the grocery store. During any given
second, the probability that a new customer joins the line is 0.02 (no
more than one customer joins the line during any given second). The
checkout clerk takes a random amount of time between 20 seconds to 75
seconds to serve each customer. Write a program to simulate this
scenario for about ten million seconds and print out the average
number of seconds that a customer spends waiting in line before the
clerk begins to serve the customer. Note that since you do not know
the maximum number of customers that may be in line at any given time,
you should use an ArrayList and not an array.
The expected average wait time is supposed to be between 500 and 600 seconds. However, I have not gotten an answer anywhere close to this range. Given that the probability of a new customer in the line is only 2%, I would expect the line to never have more than 1 person in it, so the average wait time would be about 45-50 secs. I have asked a friend (who is a math major) what his view on this problem, and he agreed that 45 seconds is a reasonable average given the 2% probability. My code so far is:
package grocerystore;
import java.util.ArrayList;
import java.util.Random;
public class GroceryStore {
private static ArrayList<Integer> line = new ArrayList();
private static Random r = new Random();
public static void addCustomer() {
int timeToServe = r.nextInt(56) + 20;
line.add(timeToServe);
}
public static void removeCustomer() {
line.remove(0);
}
public static int sum(ArrayList<Integer> a) {
int sum = 0;
for (int i = 0; i < a.size(); i++) {
sum += a.get(i);
}
return sum;
}
public static void main(String[] args) {
int waitTime = 0;
int duration = 10000;
for (int i = 0; i < duration; i++) {
double newCust = r.nextDouble();
if (newCust < .02) {
addCustomer();
}
try {
for (int j = 0; j < line.get(0); j++) {
waitTime = waitTime + sum(line);
}
} catch (IndexOutOfBoundsException e) {}
if (line.isEmpty()) {}
else {
removeCustomer();
}
}
System.out.println(waitTime/duration);
}
}
Any advice about this would be appreciated.
Here's some pseudocode to help you plan it out
for each second that goes by:
generate probability
if probability <= 0.02
add customer
if wait time is 0
if line is not empty
remove customer
generate a new wait time
else
decrement wait time
There's actually a very easy implementation of single server queueing systems where you don't need an ArrayList or Queue to stash customers who are in line. It's based on a simple recurrence relation described below.
You need to know the inter-arrival times' distribution, i.e., the distribution of times between one arrival and the next. Yours was described in time-stepped fashion as a probability of 0.02 of having a new arrival in a given tick of the clock. That equates to a Geometric distribution with p = 0.02. You already know the service time distribution - Uniform(20,75).
With those two pieces of info, and a bit of thought, you can deduce that for any given customer the arrival time is the previous customer's arrival-time plus a (generated) interarrival time; this customer can begin being served at either their arrival-time or the departure-time of the prior customer, whichever comes later; and they finish up with the server and depart at their begin-service time plus a (generated) service-time. You'll need to initialize the arrival-time and departure time of an imaginary zeroth customer to kick-start the whole thing, but then it's a simple loop to calculate the recurrence.
Since this looks like homework I'm giving you an implementation in Ruby. If you don't know Ruby, think of this as pseudo-code. It should be very straightforward for you to translate to Java. I've left out details such as how to generate the distributions, but I have actually run the complete implementation of this, replacing the commented lines with statistical tallies, and it gives average wait times around 500.
interarrival_time = Geometric.new(p_value)
service_time = Uniform.new(service_min, service_max)
arrival_time = depart_time = 0.0 # initialize zeroth customer
loop do
arrival_time += interarrival_time.generate
break if arrival_time > 10_000_000
start_time = [arrival_time, depart_time].max
depart_time = start_time + service_time.generate
delay_in_queue = start_time - arrival_time
# do anything you want with the delay_in_queue value:
# print it, tally it for averaging, whatever...
end
Note that this approach skips over the large swathes of time where nothing is happening, so it's a quite efficient little program compared to time-stepping through every tick of the simulated clock and storing things in dynamically sized containers.
One final note - you may want to ignore the first few hundred or thousand observations due to initialization bias. Simulation models usually need a "warm-up" period to remove the effect of the programmatically necessary initialization of variables to arbitrary values.
Instead of using an ArrayList, a Queue might be better suited for managing the customers. Also, remove the try/catch clause and a throws IndexOutOfBoundsException to the main function definition.
So, I have a player body + fixture etc, it is essentially a ball that bounces around.
I want to detect when it is 'pretty much' finished moving.
At the moment I do this:
public Boolean isStopped() {
return body.getLinearVelocity().x <= 0.3f && body.getLinearVelocity().y <= 0.3f;
}
This mostly works, the problem being when the player hits something, there's a split second where its velocity is 0, so this returns true. What I really wanted is to just return true when it is basically finished. Preferably within a range that I can set to whatever I like as I tweak the physics of my game world.
I can't use a check on whether it is sleeping or not as that comes too late, it doesn't sleep until after it has stopped having forces act upon it, I need just before.
I could just store how long it has been stopped/a count of stopped steps, but I was hoping there would be a nice pre existing method that I missed.
Any ideas?
You can keep track of recent movement and update it by mixing in a little of the current speed each time step:
float speedNow = body.getLinearVelocity().len();
recentSpeed = 0.1 * speedNow + 0.9 * recentSpeed;
if ( recentSpeed < someThreshold )
... do something ...
You would need to set recentSpeed to a suitably high value to begin with, otherwise it might be below the threshold in the first time step.
Seeing how you've determined that your false positives are caused by the body making contact with another, why not add a couple of lines in your ContactListener's beginContact method, storing the body's current speed in its user data? Then you can check that speed in your isStopped method. If there is a stored speed and the current speed isn't greater, this means the body is in the process of bouncing off whatever it hit: ignore. If there is a stored speed and the current speed is greater, the ball has bounced and is proceeding in some new direction: clear the stored speed. If there is no stored speed and the current speed is below your threshold, you've detected the sought situation.
In your ContactListener:
public void beginContact(Contact contact) {
Body a = contact.getFixtureA().getBody();
Body b = contact.getFixtureB().getBody();
if (a == mBall) {
a.setUserData(a.getLinearVelocity().len());
} else if (b == mBall) {
b.setUserData(b.getLinearVelocity().len());
}
}
And in your isStopped check:
public Boolean isStopped() {
float storedSpd = (Float) body.getUserData();
float currentSpd = body.getLinearVelocity().len();
if ((storedSpd > Float.MIN_VALUE) && (currentSpd > storedSpd)) {
body.setUserData(Float.MIN_VALUE);
return false;
} else {
return (currentSpd < THRESHOLD);
}
}
This is untested, but you get the idea. Also, remember to initially set the user data to Float.MIN_VALUE.
In the end I have simply passed the delta from each render call to the isStopped() method.
public Boolean isStopped(float delta) {
boolean isMoving = (
Math.abs(body.getLinearVelocity().x) >= 0.25f || Math.abs(body.getLinearVelocity().y) >= 0.25f);
if(isMoving) {
timeStopped = 0f;
return false;
} else {
timeStopped += delta;
return timeStopped >= 0.3f;
}
}
timeStopped is just a class property that starts off as zero. This does return true for the beginning of the game (before the user has made a move) but in my application that is absolutely fine. Besides which, it is true to say it has stopped in that circumstance.
I'd still love to see a way to do this without storing extra crap, since I'm guessing box2d must have this information somewhere in order to figure out if a body with zero velocity has no force acting upon or if it is just changing direction after an impact.
I am making a game that is similar to Doodle Jump, getting your player as high as possible. Now, I got my player working, and moving. But, the problem is, I don't have gravity, or anything that will make the player fall down onto the ground again. Do you guys have any idea of doing this? I tried having the player get a constant force, being pushed down at all times, but, it's not smooth, and it doesn't act like real falling. Can I have some help with making this player-falling system?
Edit:
GRAVITY = 10;
TERMINAL_VELOCITY = 300;
vertical_speed = 0;
public void fall(){
this.vertical_speed = this.vertical_speed + GRAVITY;
if(this.vertical_speed > TERMINAL_VELOCITY){
this.vertical_speed = TERMINAL_VELOCITY;
}
this.y = this.y - this.vertical_speed;
}
I made this, didn't work, shoots my player up in the air.
In the real world gravity will increase the rate of a fall by a constant amount over time (9.8 meters per second per second). You could simulate this by giving the player a vertical speed (when they jump or fall off a platform) and then subtracting a constant amount from that value every time round the main game loop so that they accelerate over time. You'll want to put a maximum limit on this (terminal velocity) otherwise when they fall a long way they could hit ludicrous speed fairly quickly. The pseudo-code would look something like this:
const GRAVITY = 10;
const TERMINAL_VELOCITY = 300;
object Player
{
int vertical_speed = 0;
int vertical_position;
function fall ()
{
this.vertical_speed = this.vertical_speed + GRAVITY;
if (this.vertical_speed > TERMINAL_VELOCITY)
{
this.vertical_speed = TERMINAL_VELOCITY;
}
this.vertical_position = this.vertical_position - this.vertical_speed;
}
}
EDIT: 9.8 Metres Per Second Per Second is correct! Please don't edit it! Acceleration is measured as change in velocity over time, expressed in metres per second per second. 9.8 meters per second per second means that after 1 second a stationary object would have accelerated enough to be travelling at 9.8 m/s. After 2 seconds, it will have attained a speed of 19.6 m/s. After 3 seconds it will have attained a speed of 29.4 m/s and so on.
I honestly don't believe I even had to explain that.
Do you know the formula for gravity?
velocity = acceleration * time
acceleration is the gravitational acceleration.
time is the amount of time that has passed.
Also,
distance = 1/2 * acceleration * time**2
A formula to compute the height of an entity with gravity at any given time is like so:
g * t ^ 2
s(t) = --------- + v * t + h
2
Where s is the function of time (time to height), g is the gravity factor (9.8 for metres), v is the original upwards velocity, and h is the original height.
Instead of having a constant force acting on the person, you need to have the person accelerate while they fall.
They should start falling with 0 velocity. Then, you should increase the force as they fall.
To do this, you will need to update their velocity over time:
Something like this:
if (stillFalling) {
velocity = velocity + (gravity_constant) * time_interval;
} else {
velocity = 0;
}
You will want to continuously update the velocity.
You will find explanations and a demo on that website. I suggest too that you read a book on physics or at least some wiki article about gravity.
From my Experience, do something like this.
public void run() {
if(velY+g>TerminalVel) {
velY=TerminalVel;
} else {
velY+=g;
}
y+=velY;
}
The method run() should be in a loop.