浮点数0.0等于一个变换位置,100.0等于另一个变换位置

时间:2016-02-25 04:00:16

标签: c#

我有一个带有遮罩的Healthbar。

我需要在Y轴上进行流体更换。

100%的位置是-185.6而0%的位置是-78.6,我希望能够有一个浮点数,其中0.0是-78.6,而100.0是-185.6,每当浮点数改变为介于两者之间时0和100它被改变为-185.6和-78.6之间的相应值。

1 个答案:

答案 0 :(得分:1)

这应该在任何两个特定值之间提供线性比例。

 import math
 import numpy as np
 import numpy.random as rand
 import numpy.linalg as linalg

from tkinter import Tk, Frame, Canvas

class ArrayPQ:
def __init__(self, num_balls):
    self.collisionNodes = np.array([])
    self.pastCollisions = np.zeros(num_balls)

def parent(self, i):
    return (i-1) // 2

def right(self, i):
    return (i*2) + 1

def left(self, i):
    return (i*2) + 2

def insert(self, i, j, value, num_collisions_i, num_collisions_j):
    self.pastCollisions[i] = num_collisions_i
    self.pastCollisions[j] = num_collisions_j
    self.collisionNodes = np.append(self.collisionNodes, node.nodeinit(self, i, j, value, num_collisions_i, num_collisions_j))
    self.heapify1(i)

def heapify1(self, i):
    l = self.left(i)
    r = self.right(i)
    end = len(self.collisionNodes)
    top = i
    if l < end and self.collisionNodes(i) < self.collisionNodes(l):
        top = l
    if r < end and self.collisionNodes(top) < self.collisionNodes(r):
        top = r
    if max != i:
        self.swap(i, top)
        self.heapify1(top)

def heapify2(self, i):
   if self.right(i) + len(self.collisionNodes)

def delete(self, i):
    self.swap(self, 0, (len(self.collisionNodes) -1))
    del self.collisionNodes[len(self.collisionNodes)-1]
    self.heapify1(i)

def swap(self, i, j):
    self.collisionNodes[i], self.collisionNodes[j] = self.collisionNodes[j],  
    self.collisionNodes[i]

def get_next(self):
    temp = self.collisionsNodes[0]
    return temp.BBi, temp.BBj, temp.T, temp.CCi, temp.CCj
class node:
def nodeinit(self, Bi, Bj, T, Ci, Cj):
    self.BBi = Bi
    self.BBj = Bj
    self.TT = T
    self.CCi = Ci
    self.CCj = Cj


class Painter:
#__init__ performs the construction of a Painter object
def __init__(self, root, scale=500, border=5, refresh_speed=5, 
filename='balls.txt', min_radius=5, max_radius=10, num_balls=20):
    #width and height are used to set the simulation borders
    width = scale + border
    height = scale + border
    self.time = 0
    #setup will set up the necessary graphics window and the ball list
    self.setup(root, width, height, border, refresh_speed)
    #Check the input parameter 'filename' to load predetermined simulation
    #otherwise set up the default simulation
    if filename is None:
        self.init_balls(max_radius, min_radius, num_balls)
        self.num_balls = num_balls
    else:
        self.num_balls = self.read_balls(scale, filename)
    #Create the priority data structure
    self.PQ = ArrayPQ(self.num_balls)
    #Initialize all possible collision times
    self.init_ball_collision_times()
    self.init_wall_collision_times()
    #draw will draw the graphics to the window
    self.draw()
    #refresh is a loop method intended to create animations
    self.refresh()
    #A blank return indicates the end of the function
    return

#setup creates the window to display the graphics along with the red border
#of the simulation
def setup(self, root, width, height, border, refresh_speed):
    # Draw frame etc
    self.app_frame = Frame(root)
    self.app_frame.pack()
    self.canvas = Canvas(self.app_frame, width = width, height = height)
    self.canvas_size = (int(self.canvas.cget('width')), 
    int(self.canvas.cget('height')))
    self.canvas.pack()
    self.refresh_speed = refresh_speed

    # Work area
    self.min_x = border
    self.max_x = width - border
    self.min_y = border
    self.max_y = height - border
    #create array to hold the n number of balls
    self.balls = []
    self.ball_handles = dict()        

    return


def read_balls(self, scale, filename):
    f = open(filename)
    num_balls = int(f.readline().strip())

    for l in f:
        ll = l.strip().split(" ")
        x = scale*float(ll[0])
        y = scale*float(ll[1])
        vx = scale*float(ll[2])
        vy = scale*float(ll[3])
        radius = scale*float(ll[4])
        mass = float(ll[5])
        r = int(ll[6])
        g = int(ll[7])
        b = int(ll[8])
        tk_rgb = "#%02x%02x%02x" % (r, g, b)            
        new_ball = Ball(radius, x, y, vx, vy, mass, tk_rgb)
        self.balls.append(new_ball)
    return num_balls


def init_balls(self, max_radius, min_radius, num_balls):
    for i in np.arange(num_balls):
        while(True):
            radius = (max_radius - min_radius) * rand.random_sample() + 
            min_radius

            ball_min_x = self.min_x + radius
            ball_max_x = self.max_x - radius
            x = (ball_max_x - ball_min_x)*rand.random_sample() + ball_min_x

            ball_min_y = self.min_y + radius
            ball_max_y = self.max_y - radius                
            y = (ball_max_y - ball_min_y)*rand.random_sample() + ball_min_y

            vx = rand.random_sample()
            vy = rand.random_sample()

            mass = 1.0 # rand.random_sample()
            new_ball = Ball(radius, x, y, vx, vy, mass)

            if not new_ball.check_overlap(self.balls):
                self.balls.append(new_ball)
                break

#init_wall_collision_times will set all of the balls' minimum collision time
def init_wall_collision_times(self):
    for i in np.arange(len(self.balls)):
        bi = self.balls[i]
        tix = bi.horizontal_wall_collision_time(self.min_x, self.max_x)
        tiy = bi.vertical_wall_collision_time(self.min_y, self.max_y)
        self.PQ.insert(i, -1, tix + self.time, self.balls[i].count, -1)
        self.PQ.insert(-1, i, tiy + self.time, -1, self.balls[i].count)
    return

#init_ball_collision_times will set all of the balls' minimum collision time
#with all other balls and store that time within the ith and jth index of
#PQ.ball_collision_time
def init_ball_collision_times(self):
    for i in np.arange(self.num_balls):
        bi = self.balls[i]
        for j in np.arange(i+1, self.num_balls):
            bj = self.balls[j]
            tij = bi.ball_collision_time(bj)
            self.PQ.insert(i, j, tij + self.time, self.balls[i].count, 
            self.balls[j].count)
            # self.ball_collision_times[i][j] = tij
            # self.ball_collision_times[j][i] = tij
    return

#walls (horizontal and vertical) and all other balls within the PQ array
def update_collision_times(self, i):
    bi = self.balls[i]
    tix = bi.horizontal_wall_collision_time(self.min_x, self.max_x)
    tiy = bi.vertical_wall_collision_time(self.min_y, self.max_y)
    self.PQ.insert(i, -1, tix + self.time,self.balls[i].count, -1)
    self.PQ.insert(-1, i, tiy + self.time, -1, self.balls[i].count)
    for j in np.arange(self.num_balls):
        bj = self.balls[j]
        tij = bi.ball_collision_time(bj) + self.time
        if i > j:
            self.PQ.insert(j, i, 
        tij,self.balls[j].count,self.balls[i].count)
        else:
            self.PQ.insert(i, j, tij,self.balls[i].count, 
    self.balls[j].count)
    return

#draw will draw the borders and all balls within self.balls
def draw(self):
    #Draw walls
    self.canvas.create_line((self.min_x, self.min_y), (self.min_x, 
    self.max_y), fill = "red")
    self.canvas.create_line((self.min_x, self.min_y), (self.max_x, 
    self.min_y), fill = "red")
    self.canvas.create_line((self.min_x, self.max_y), (self.max_x, 
    self.max_y), fill = "red")
    self.canvas.create_line((self.max_x, self.min_y), (self.max_x, 
    self.max_y), fill = "red")
    #Draw balls        
    for b in self.balls:
        obj = self.canvas.create_oval(b.x - b.radius, b.y - b.radius, b.x +  
        b.radius, b.y + b.radius, outline=b.tk_rgb, fill=b.tk_rgb)
        self.ball_handles[b] = obj
    self.canvas.update()


#refresh is called to update the state of the simulation
#-each refresh call can be considered one iteration of the simulation
def refresh(self):
    #get the next collision
    i, j, t, num_collisions_i, num_collision_j  = self.PQ.get_next()
    #gather the current collisions of the ith and jth ball
    current_collisions_i = self.balls[i].count
    current_collisions_j = self.balls[j].count

    #Check the difference in time between the predicted collision time and 
    #the current time stamp of the simulation
    delta = t - self.time
    #If the difference is greater than 1, then just move the balls
    if delta > 1.0:
        # cap delta to 1.0
        for bi in self.balls:
            bi.move()
            self.canvas.move(self.ball_handles[bi], bi.vx, bi.vy)
        self.time += 1.0
    #Otherwise a collision has occurred
    else:
        #Move all balls
        for bi in self.balls:
            bi.move(delta)
            self.canvas.move(self.ball_handles[bi], bi.vx*delta, 
         bi.vy*delta)
        #increment the simulation time stamp
        self.time += delta
        #Delete the top element within the Priority Queue
        self.PQ.delete()
        #if i is -1 then this indicates a collision with a vertical wall
        #also this if statement checks if the number of collisions recorded 
        #when the collision returned by PQ.get_next() is equal to the 
        #number of collisions within the jth ball
        #this acts as a test to check if the collision is still valid
        if i == -1 and num_collision_j == current_collisions_j:
            #compute what happens from the vertical wall collision
            self.balls[j].collide_with_vertical_wall()
            #update collision times for the jth ball
            self.update_collision_times(j)
        #if j is -1 then this indicates a collision a horizontal wall
        #while also checking if the number of collisions match
        #to see if the collision is valid
        elif j == -1 and num_collisions_i == current_collisions_i:
            #compute what happens from the horizontal wall collision
            self.balls[i].collide_with_horizontal_wall()
            #update collision times for the ith ball
            self.update_collision_times(i)

        elif num_collision_j == current_collisions_j and num_collisions_i ==  

        current_collisions_i:
            #Execute collision across the ith and jth ball                
            self.balls[i].collide_with_ball(self.balls[j])
            #update collision times for both the ith and jth ball
            self.update_collision_times(i)
            self.update_collision_times(j)

    #update the canvas to draw the new locations of each ball
    self.canvas.update()

    self.canvas.after(self.refresh_speed, self.refresh)
def __init__(self, radius, x, y, vx, vy,  mass, tk_rgb="#000000"):
    self.radius = radius
    self.x = x
    self.y = y
    self.vx = vx
    self.vy = vy
    self.mass = mass
    self.tk_rgb = tk_rgb

    #since this ball was just initialized, it hasn't had any collisions yet
    self.count = 0
    return

#move changes the displacement of the ball by the velocity
def move(self, dt=1.0):
    self.x += self.vx*dt
    self.y += self.vy*dt
    return

#check_overlap checks if this ball is overlapping with any other
#ball, it is used to see if a collision has occurred
def check_overlap(self, others):
    for b in others:
        min_dist = b.radius + self.radius
        center_dist = math.sqrt((b.x - self.x)*(b.x - self.x) + \
                                (b.y - self.y)*(b.y - self.y))
        if center_dist < min_dist:
            return True
    return False

#collide_with_ball computes collision, changing the Ball's velocity
#as well as the other ball's velocity
def collide_with_ball(self, other):
    dv_x = other.vx - self.vx
    dv_y = other.vy - self.vy

    dr_x = other.x - self.x
    dr_y = other.y - self.y

    sigma = self.radius + other.radius

    dv_dr = dv_x * dr_x + dv_y * dr_y

    J = 2.0 * self.mass * other.mass * dv_dr/((self.mass + 

    other.mass)*sigma)
    Jx = J * dr_x/sigma
    Jy = J * dr_y/sigma

    self.vx += Jx/self.mass
    self.vy += Jy/self.mass

    other.vx -= Jx/other.mass
    other.vy -= Jy/other.mass
    #Increment the collision count for both balls
    self.count += 1
    other.count += 1
    return

# Compute when an instance of Ball collides with the given Ball other
# Return the timestamp that this will occur
def ball_collision_time(self, other):

    dr_x = other.x - self.x
    dr_y = other.y - self.y

    if dr_x == 0 and dr_y == 0:
        return float('inf')

    dv_x = other.vx - self.vx
    dv_y = other.vy - self.vy

    dv_dr = dv_x * dr_x + dv_y * dr_y

    if dv_dr > 0:
        return float('inf')

    dv_dv = dv_x * dv_x + dv_y * dv_y
    dr_dr = dr_x * dr_x + dr_y * dr_y
    sigma = self.radius + other.radius

    d = dv_dr * dv_dr - dv_dv * (dr_dr - sigma * sigma) 

    # No solution 
    if d < 0 or dv_dv == 0:
        return float('inf')
    return - (dv_dr + np.sqrt(d))/dv_dv

#collide_with_horizontal_wall executes the change in the Ball's
#velocity when colliding with a horizontal wall
def collide_with_horizontal_wall(self):
    self.vx = -self.vx
    self.count += 1
    return
#collide_with_vertical_wall executes the change in the Ball's
#velocity when colliding with a vertical wall
def collide_with_vertical_wall(self):
    self.vy = -self.vy
    self.count += 1
    return

# Compute when the instance of Ball collides with a horizontal wall
# Return the time stamp that this will occur 
def horizontal_wall_collision_time(self, min_x, max_x):
    if self.vx < 0:
        # x + delta_t * vx = min_x + radius
        return (min_x + self.radius - self.x)/(1.0*self.vx)

    if self.vx > 0:
        # x + delta_t * vx = max_x - radius
        return (max_x - self.radius - self.x)/(1.0*self.vx)

    return float('inf')

# Compute when the instance of Ball collides with a vertical wall
# Return the time stamp that this will occur 
# Inputs of min_y and max_y 
def vertical_wall_collision_time(self, min_y, max_y):
    if self.vy < 0:
        # y + delta_t * vy = min_y + radius
        return (min_y + self.radius - self.y)/(1.0*self.vy)

    if self.vy > 0:
        # y + delta_t * vy = max_y - radius
        return (max_y - self.radius - self.y)/(1.0*self.vy)

    return float('inf')

#show_stats will print out the Ball's data
#specifically the radius, position, velocity, mass, and color
def show_stats(self):
    print("radius: %f"%self.radius)
    print("position: %f, %f"%(self.x, self.y))
    print("velocity: %f, %f"%(self.vx, self.vy))
    print("mass: %f"%self.mass)
    print("rgb: %s"%self.tk_rgb)
    return


#Main script
if __name__ == "__main__":

#Set the parameters for the graphics window and simulation
scale = 800
border = 5
#Set radius range for all balls
max_radius = 20
min_radius = 5
#set number of balls
num_balls = 10
#set refresh rate
refresh_speed = 5
rand.seed(12394)
#create the graphics object
root = Tk()
#Create the painter object
p = Painter(root, scale, border, refresh_speed, None, min_radius,max_radius,    

 num_balls)
#If you have the commented out files in your directory then
#uncomment them to see what they do
#p = Painter(root, scale, border, refresh_speed, 'wallbouncing.txt')
#p = Painter(root, scale, border, refresh_speed, 'p10.txt')
#p = Painter(root, scale, border, refresh_speed, 'billiards4.txt')
#p = Painter(root, scale, border, refresh_speed, 'squeeze.txt')

#run the Painter main loop function (calls refresh many times)
root.mainloop()

更通用的方法是

float scale(float percent) {
  float min = -185.6;
  float max = -78.6;
  return min + ((max-min)*percent);
}

你不能传递任何两个值,并在它们之间获得一定的值。不假设a小于b。