Hikaroshi's Profile User Rating: -----

Reputation: 8 Worker
Group:
Members
Active Posts:
42 (0.02 per day)
Joined:
26-April 09
Profile Views:
2,272
Last Active:
User is offline Nov 14 2013 09:29 AM
Currently:
Offline

Previous Fields

Dream Kudos:
0

Latest Visitors

Icon   Hikaroshi has not set their status

Posts I've Made

  1. In Topic: Undefined variable error with a method

    Posted 6 Sep 2013

    To add on to that explanation above, with the code you have posted, your code runs line by line. Once it reaches that function call, it doesn't recognize the function because it did not reach that line where the function is created, which happens after you try to call it. Like this link. If you step through it, you realize what is going on. It would technically work if the call happened after the program had reached that line and created a pointer to location of the function definition, like in this example.

    If you have everything in a function, the program will run line by line, but in a different sense. It will go from top to bottom and point to where each function is defined, but will only execute (explore the contents of the function) the function if it is called. In the case of this last example if newFunction() was not called on the last line of the program, the program would just contain pointers to the functions but would not execute anything because none of the functions were called. Then from there, newFunction() calls the other function on line 7.
  2. In Topic: Stuck on ball collision

    Posted 2 Sep 2013

    @baavgai: Thank you for your response. Wish I saw it earlier. You're right though, objects would be better suited for this. I was doing it exactly as the assignment requirements at that time (using functions), but as I realized I needed more functions to do things, I started to wonder if OOP would be better suited for this.

    In your 'code sketch' we would have a class that bridges the ball class and square class together. From there, the square objects would still get pushed into a list, and that's what gets passed in the Square class and also in methods like isInsideSquare(), correct?

    Since I didn't see your response until now, I managed to get a little further on the ball collision logic. I think it's significantly better now, and if I stopped right now I would feel pretty okay. Sometimes the balls would get pushed out of bounds by the other ball because I created a while loop inside of the collision detection function but couldn't wrap my mind around creating another function to do that check. Then I realized it would be more efficient if I could reuse that hypothetical function for the two if statements in simul() that check for collision at the bounds of the screen. I left the black box thing alone, but figured it was almost the same as the while loop in the hasCollided() function. Then I realized that I would have to consider the balls going out of bounds based on the original direction of the ball relative to the location of the black box and whether it's at a corner. I think I might call it quits, but I wouldn't mind an explanation on what I could have done for the case of screen bound checking + the while loop and the black box (balls still getting stuck and jiggling) OOP or not is fine.


    I edited the "if boolVal == True" statement in simul based on the changes I made in the "if (dist <= (r1 + r2)):" statement until the end of that function. I created a function called "isSameSign()" and attempted to do something with another function called "isInBounds()".

    from graphics import *
    from math import *
    import random
    
    W = 300
    H = 300
    ballList = []
    squareList = []
    
    #----------------------------------------------------------------
    def simul(win, ballList):
        for step in range( 200 ):
            for i in range(len(ballList)):
                c, dx, dy = ballList[i]
                x = c.getCenter().getX()
                y = c.getCenter().getY()
                r = c.getRadius()
    
                if (x  <= 0 + r ) or (x >= W - r):
                    dx = -dx
                if (y <= 0 + r) or(y >= H - r):
                    dy = -dy
    
                # stop the ball's movement
                if isInSquare(x, y, r):
                    dx = 0
                    dy = 0
    
                # make it bounce off the black box's bounds
                if hitBlackBox(x, y, r):
                    dx = -dx
                    dy = -dy
    
                (boolVal, ball1, ball2) = hasCollided(ballList) # create a tuple
                if boolVal == True:
                    # change the dx and dy of each ball that satisfies condition
                    # then reverse the dx, dy of collided balls
                    c1, dx1, dy1 = ball1
                    c2, dx2, dy2 = ball2
    
                    # replace old ballList values with current ballList values
                    for list in ballList:
                        if ball1[0] in list:
                            list.pop(1)
                            list.insert(1, dx1)
                            list.pop(2)
                            list.insert(2, dy1)
                        if ball2[0] in list:
                            list.pop(1)
                            list.insert(1, dx2)
                            list.pop(2)
                            list.insert(2, dy2)
                    c1.move(dx1, dy1)
                    c2.move(dx2, dy2)
    
                else:
                    c.move(dx, dy)
                    ballList[ i ] = [ c, dx, dy ] # update ball values
    
                if allInBoxes(ballList):
                    end(win)
    
    def allInBoxes(ballList):
        counter = 0
        for i in range(len(ballList)):
            c, dx, dy = ballList[i]
            if (dy == dx == 0):
                counter += 1
        if counter == len(ballList):
            return True
        return False
    
    def hasCollided(ballList):
        newBallList = []
        for i in range(len(ballList)-1):
            for j in range(i+1, len(ballList)):
                c1 = ballList[i][0]
                c2 = ballList[j][0]
                # get the dx1-2, dy1-2 vals
                dx1 = ballList[i][1]
                dy1 = ballList[i][2]
                dx2 = ballList[j][1]
                dy2 = ballList[j][2]
                # get radius of i and j balls
                r1 = c1.getRadius()
                r2 = c2.getRadius()
                # now get the points
                P1 = Point(c1.getCenter().getX(), c1.getCenter().getY())
                P2 = Point(c2.getCenter().getX(), c2.getCenter().getY())
                #print "(", P1.getX(), ",",P1.getY(),")", "(" , P2.getX() , ",",P2.getY(),")", "This is P1, P2"
                dist = distance(P1, P2)
                if (dist <= (r1 + r2)):
                    if isSameSign(dx1, dx2): # push away one ball if sign's same
                        dx1 = -dx1
                    elif isSameSign(dy1, dy2):
                        dy1 = -dy1
                    else: # assume opposing sign, intend to push away each ball
                        dx1 = -dx1
                        dy1 = -dy1
                        dx2 = -dx2
                        dy2 = -dy2
                    while (dist <= (r1 + r2)):
                        c1.move(dx1, dy1)
                        c2.move(dx2, dy2)
                        P1 = Point(c1.getCenter().getX(), c1.getCenter().getY())
                        P2 = Point(c2.getCenter().getX(), c2.getCenter().getY())
                        dist = distance(P1, P2) # call again, get updated points
    
                    newBallList.append([c1, dx1, dy1])
                    newBallList.append([c2, dx2, dy2])
                    return True, newBallList[0], newBallList[1]
        return False, 0, 0
    
    def distance(P1, P2):
        return sqrt( pow( P1.getX() - P2.getX(), 2 ) + pow( P1.getY() - P2.getY(), 2 ))
    
    def isSameSign(a, B)/>/>/>/>:
        # check if both signs are same
        if ((a < 0) and (b < 0)) or ((a > 0) and (b > 0)):
            return True
    
    # Complete but incomplete concept (not implemented):
    # This function is to assist the while loop in the collision check
    # to ensure the balls don't knock each other out of the screen.
    # I was going to integrate this in the while loop above and
    # find the ball that is not closest to the bounds and push
    # that one in the opposite direction, then bounce the other one.
    # I've been working on this program for a few days, I think it's better
    # to do something else now, so I'll leave this incomplete.
    def isInBounds(c1, c2):
        boundsList = []
        boundsList.append(c1)
        boundsList.append(c2)
        for i in range(len(boundsList)):
            r = boundsList[i].getRadius()
            x = boundsList[i].getCenter().getX()
            y = boundsList[i].getCenter().getY()
            if ((x  <= 0 + r ) or (x >= W - r)) or ((y <= 0 + r) or(y >= H - r)):
                return False
            return True
    
    def isInSquare(x, y, r):
        for i in range(len(squareList)-1): # exclude black box
            sP1 = squareList[i].getP1() # (bOriginX, bOriginY)
            sP2 = squareList[i].getP2() # (bW, bH)
    
            if (sP2.getX() - r >= x >= sP1.getX() + r) and (sP2.getY() - r >= y >= sP1.getY() + r):
                return True
    
    # Another complete but incomplete concept.
    # I was going to do make the code push out
    # any balls that are already inside/go inside the black box.
    # It's pretty much like the while loop, but I think it's better
    # to move on. On to another project!
    def hitBlackBox(x, y, r):
        # get last box
        blackBox = squareList[-1]
        sP1 = blackBox.getP1() # (bOriginX, bOriginY) | square P1
        sP2 = blackBox.getP2() # (bW, bH) | square P2
        if (sP2.getX() + r >= x >= sP1.getX() - r) and (sP2.getY() + r >= y  >= sP1.getY() - r):
            return True
    
    def drawSquare(win):
        for i in range(4): # create 3 white boxes with random coords
            bOriginX = random.randrange(0, W-50, 51)
            bOriginY = random.randrange(0, H-100, 51)
            bW = bOriginX + 50 # you have to include origin + width therefore 100-50 = 50 sBoxW
            bH = bOriginY + 50
            square = Rectangle(Point(bOriginX, bOriginY), Point(bW, bH))
            square.draw(win)
            square.setFill("white")
            squareList.append(square)
        squareList[-1].setFill("black") # Fill last square drawn with black
    
    # this commented portion can work too, remove the previous line, set loop range(3)
    ##    blackSquare = Rectangle(Point(H-50,W-50), Point((W-50)+50, (H-50)+ 50))
    ##    blackSquare.draw(win)
    ##    blackSquare.setFill("black")
    ##    squareList.append(blackSquare)
    
    # -------------------------------------------
    def end(win):
        waitForClick( win, "Click to End" )
        win.close()
    
    
    #----------------------------------------------------------------
    def waitForClick( win, message ):
        """ waitForClick: stops the GUI and displays a message.
        Returns when the user clicks the window. The message is erased."""
    
        # wait for user to click mouse to start
        startMsg = Text( Point( win.getWidth()/2, win.getHeight()/2 ), message )
        startMsg.draw( win )    # display message
        win.getMouse()          # wait
        startMsg.undraw()       # erase
    
    #----------------------------------------------------------------
    def main():
        win = GraphWin( "moving ball", W, H )
        #--- define a ball position and velocity ---
        drawSquare(win)
        ballColor = ["red", "blue", "pink", "purple", "green"]
        for i in range(5):
            c = Circle( Point( random.randrange( 16, W-15, 20 ), random.randrange( H/3, 2*H/3, 20 ) ), 15 )
            c.setFill(ballColor[i%len(ballColor)])
            c.draw(win)
            ballList.append([c, 5 - random.randrange(10), 5 - random.randrange(10)])
    
        for i in range(len(ballList)): # loop: no ball should be 0 dx and 0 dy
            if ballList[i][1] == ballList[i][2] == 0:
                ballList[i][1] == 1
    
        waitForClick( win, "Click to Start" )
    
        simul(win, ballList)
        end(win)
    
    main()
    


    @woooee: I think I understand what you're talking about. I would have thought with the same distance formula it wouldn't make a difference unless you mean making the ball move based on its initial direction before the collision call changes the direction to -dx, -dy.

My Information

Member Title:
New D.I.C Head
Age:
Age Unknown
Birthday:
Birthday Unknown
Gender:

Contact Information

E-mail:
Private

Friends

Comments

Hikaroshi has no profile comments yet. Why not say hello?