Advertisement
Guest User

Untitled

a guest
Aug 1st, 2017
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 19.47 KB | None | 0 0
  1. extends KinematicBody2D
  2.  
  3. onready var state   = BatHugState.new(self) #this creates a new instance of the state.  It will call the states _init function of course kicking it all off
  4. onready var camera  = get_node("/root/gameLevel/Camera2D")
  5.  
  6. var ballDiameter                        #we need this right?  Course we do
  7. var _gravity            = .5            # Gravity
  8. var _movement           = Vector2()     # Movement
  9. var bounce              = 1             # Bounce reduction
  10. var shakeAmount         = 2             # for screen shake
  11. var timer                               # for screen shake
  12. var timerLength         = .15           # for screen shake
  13. var shakeAllowed        = false         # for screen shake
  14. var initialBallSpeed    = -5            # how fast is this ball anyway?
  15. var speedIncrement      = 1             # speed up when using powerup
  16. var powerBall           = false         # can we smash bricks like butter?!
  17.  
  18. var batOffset           = Vector2(0,0)  #find the difference between the bat's centre and where the ball hit it
  19.  
  20. const STATE_MOVING      = 0
  21. const STATE_BATHUG      = 1
  22. const STATE_LEVELOVER   = 2
  23. const STATE_BATMAGNET   = 3
  24. const STATE_MULTILAUNCH = 4
  25. const MAXBOUNCEANGLE    = deg2rad(160)  #the max bounce angle (in radians) of the ball when hitting the edge of the bat
  26.  
  27. signal levelOver
  28. signal hitWall
  29.  
  30. func _ready():
  31.    
  32.     #setup the timer for camera shakey shake!
  33.     timer = Timer.new()                 #create an instance of the timer
  34.     timer.set_one_shot(true)            #only count down once then stop
  35.     timer.set_wait_time(timerLength)    #how long the timer runs for
  36.     add_child(timer)                    #make it a child of this ball instance
  37.    
  38.     set_process_input(true)
  39.     set_fixed_process(true)
  40.  
  41.     ballDiameter = get_node("Sprite").get_texture().get_width() #good to know how large this sprite is
  42.     add_to_group("balls")   #so we can bulk process them later if required
  43.  
  44.     #force bathug for now
  45.     state = BatHugState.new(self)
  46.  
  47.  
  48. func _fixed_process(delta):
  49.    
  50.     #call the update function within the state class.  Very cool
  51.     #It doesn't matter which state we're in, this will call the function with the same name in each class that is "state" as per the onready above
  52.     state.update(delta)
  53.    
  54. func _input(event):
  55.     #call the input function from within the state class. Clevs
  56.     state.input(event)
  57.  
  58. #dust puff off wallls
  59. func makeDust():
  60.     var scene = load("res://dustBall.tscn")
  61.     var sceneInstance = scene.instance()
  62.     get_node("/root/gameLevel").add_child(sceneInstance)   
  63.  
  64. #powerup changes this to make ball faster
  65. func changeBallSpeed(newSpeed):
  66.     if globals.ballState == "fast":
  67.         speedIncrement = newSpeed
  68.     elif globals.ballState == "slow":
  69.         speedIncrement = newSpeed
  70.  
  71.  
  72. #total reset of ball speed
  73. func resetBallSpeed():
  74.     speedIncrement = 1
  75.    
  76. #make ball powerupBall
  77. func makePowerBall():
  78.     powerBall = true
  79.    
  80. #take away powerBall powers
  81. func removePowerBall():
  82.     powerBall = false
  83.  
  84.  
  85. func shakeTheCamera():
  86.     #camera shake!
  87.     if timer.get_time_left() > 0:
  88.         camera.set_offset(Vector2(rand_range(-1.0, 1.0) * shakeAmount, rand_range(-1.0, 1.0) * shakeAmount))
  89.     else:
  90.         camera.set_offset(Vector2(0, 0))
  91.  
  92.  
  93. func set_state(new_state):
  94.     #first exit the current state
  95.     state.exit()
  96.    
  97.     #now choose the next state
  98.     if new_state == STATE_BATHUG:
  99.         state = BatHugState.new(self)
  100.     elif new_state == STATE_MOVING:
  101.         state = MoveState.new(self)
  102.     elif new_state == STATE_LEVELOVER:
  103.         state = LevelOverState.new(self)
  104.     elif new_state == STATE_BATMAGNET:
  105.         state = BatMagnetState.new(self)
  106.     elif new_state == STATE_MULTILAUNCH:
  107.         state = MultiLaunchState.new(self)
  108.  
  109.  
  110.  
  111. #######################################################################################
  112. # class Move State --------------------------------------------------------------------
  113. #######################################################################################
  114. class MoveState:
  115.     var ball
  116.        
  117.     #init gets called when an object of this class gets created
  118.     func _init(ball):
  119.         self.ball = ball
  120.         #choose a random launch angle
  121.         randomize()
  122.         var direction = range(-3,5)[randi()%range(-3,5).size()]
  123.         #send it skyward
  124.         launch(Vector2(direction,ball.initialBallSpeed)) #directional force
  125.  
  126.     # Initialize shot from another script after adding it to the scene
  127.     func launch(directional_force):
  128.         ball._movement = directional_force
  129.         #play launch sound
  130.         ball.get_parent().get_node("SamplePlayer2D").play("launchBall02")
  131.  
  132.     #frame by frame update
  133.     func update(delta):
  134.         # Simulate gravity
  135.         ball._movement.y += delta * ball._gravity
  136.        
  137.         #do screen shake (triggered below if we colide)
  138.         if ball.timer.is_active():
  139.             ball.shakeTheCamera()
  140.  
  141.         # Check if we have collided
  142.         if(ball.is_colliding()):
  143.             #shake the camera
  144.             ball.timer.start()
  145.             ball.shakeAllowed = true
  146.             # Get node that we are colliding with
  147.             var entity = ball.get_collider()
  148.             #if there is a ball
  149.             if entity:
  150.                 #if this is a hit against the bat
  151.                 if entity.get_name() == "bat":
  152.                     #first check if we're in magnet bat powerup state
  153.                     var bat = ball.get_node("/root/gameLevel/bat")
  154.                     if bat.readState() == "magnet":
  155.                         #store the location the ball hit the bat, so the hug state knows how much to offset
  156.                         ball.batOffset = ball.get_pos()
  157.                         #change the ball state to be magnetic to the bat
  158.                         ball.set_state(STATE_BATMAGNET)
  159.                     else:
  160.                         #play a sound
  161.                         ball.get_parent().get_node("SamplePlayer2D").play("ballHit01")
  162.                         #reflect ball angle depending on where we hit it with the bat
  163.                         findCollisionAreaOnBat("bat", delta)
  164.    
  165.                 # Apply physics
  166.                 var normal = ball.get_collision_normal()
  167.            
  168.                 #reduce 1 from the number of hits remaining on the brick, so as we might DESTROY said brick!
  169.                 if entity.get_parent().is_in_group("bricks"):
  170.                     #do we have powerBall
  171.                     if ball.powerBall:
  172.                    
  173.                         #If the brick still has some strength left in it
  174.                         if entity.get_parent().get("numOfHitsRequired") >= 2:
  175.                             #play a hit sound
  176.                             ball.get_node("/root/gameLevel").get_node("SamplePlayer2D").play("brickHit0")
  177.                             #reduce number of hits the brick has, as we just hit it.
  178.                             var brickNumHits = int((entity.get_parent().get("numOfHitsRequired") -1))
  179.                             entity.get_parent().numOfHitsRequired = brickNumHits
  180.                         #otherwise, the brick must be destroyed
  181.                         else:
  182.                             #create a powerup as we break the brick
  183.                             if entity.get_parent().powerupName != "none":   #there must be a powerup if it doesn't equal "none"
  184.                                 #create /instance the new powerup
  185.                                 var powerupScene = load("res://fallingPowerup.tscn")
  186.                                 var newpowerup = powerupScene.instance()
  187.                                 #set the type of powerup
  188.                                 newpowerup.setPowerupType(entity.get_parent().powerupName)
  189.                                 #set powerup texture
  190.                                 var textureString = "res://textures/"+entity.get_parent().powerupName+".png"
  191.                                 var textureToUse = load(textureString)
  192.                                 newpowerup.get_node("Sprite").set_texture(textureToUse)
  193.                                 #set powerup Position to where ball is now
  194.                                 newpowerup.set_pos(Vector2(ball.get_pos().x,ball.get_pos().y))
  195.                                 #create the powerup
  196.                                 ball.get_tree().get_root().add_child(newpowerup)
  197.                                 #add it to a group
  198.                                 newpowerup.add_to_group("powerups")
  199.                                 #move it downward, so we might catch it!
  200.                                 newpowerup.set_linear_velocity(Vector2(0,0))
  201.                             #then destroy the brick
  202.                             if entity.get_parent().has_method("destroyThisBrick"):
  203.                                 entity.get_parent().destroyThisBrick()
  204.                                 #check if there are no bricks left and if not, level over
  205.                                 if ball.get_tree().get_nodes_in_group("bricks").size() <= 1:
  206.                                     #change the ball state, we don't want it moving or showing anymore
  207.                                     ball.set_state(STATE_LEVELOVER)
  208.                                     #show the congrats scene
  209.                                     ball.get_parent().get_node("levelFinished").showScene()
  210.                                     ball.get_parent().get_node("levelFinished").updateLabels()
  211.                                     #remove any leftover balls
  212.                                     var ballList = ball.get_tree().get_nodes_in_group("balls")
  213.                                     for i in ballList:
  214.                                         i.queue_free()
  215.                     else:
  216.                         #create a powerup as we break teh brick
  217.                         if entity.get_parent().powerupName != "none":   #there must be a powerup if it doesn't equal "none"
  218.                             #create /instance the new powerup
  219.                             var powerupScene = load("res://fallingPowerup.tscn")
  220.                             var newpowerup = powerupScene.instance()
  221.                             #set the type of powerup
  222.                             newpowerup.setPowerupType(entity.get_parent().powerupName)
  223.                             #set powerup texture
  224.                             var textureString = "res://textures/"+entity.get_parent().powerupName+".png"
  225.                             var textureToUse = load(textureString)
  226.                             newpowerup.get_node("Sprite").set_texture(textureToUse)
  227.                             #set powerup Position to where ball is now
  228.                             newpowerup.set_pos(Vector2(ball.get_pos().x,ball.get_pos().y))
  229.                             #create the powerup
  230.                             ball.get_tree().get_root().add_child(newpowerup)
  231.                             #add it to a group
  232.                             newpowerup.add_to_group("powerups")
  233.                             #move it downward, so we might catch it!
  234.                             newpowerup.set_linear_velocity(Vector2(0,0))
  235.                         #then destroy the brick
  236.                         if entity.get_parent().has_method("destroyThisBrick"):
  237.                             entity.get_parent().destroyThisBrick()
  238.                             #check if there are no bricks left and if not, level over
  239.                             if ball.get_tree().get_nodes_in_group("bricks").size() <= 1:
  240.                                 #change the ball state, we don't want it moving or showing anymore
  241.                                 ball.set_state(STATE_LEVELOVER)
  242.                                 #show the congrats scene
  243.                                 ball.get_parent().get_node("levelFinished").showScene()
  244.                                 ball.get_parent().get_node("levelFinished").updateLabels()
  245.                                 #remove any leftover balls
  246.                                 var ballList = ball.get_tree().get_nodes_in_group("balls")
  247.                                 for i in ballList:
  248.                                     i.queue_free()
  249.    
  250.                         # Apply bounce physics, simply use normal.reflect x the bounce strength variable
  251.                         ball._movement = normal.reflect(ball._movement) * ball.bounce  
  252.  
  253.  
  254.  
  255.                 #did we hit a wall?
  256.                 elif entity.get_parent().is_in_group("walls"):
  257.                     #so bad I know, but am storing the ball X and Y for dust ball creation and placement. Over it, just doing this to get it done.
  258.                     globals.ballX = ball.get_pos().x
  259.                     globals.ballY = ball.get_pos().y
  260.                     # Apply bounce physics, simply use normal.reflect x the bounce strength variable
  261.                     #ball._movement.y+=.0005
  262.                     ball._movement = normal.reflect(Vector2(ball._movement.x, ball._movement.y)) * ball.bounce
  263.                     #play the wall hit sound
  264.                     ball.get_parent().get_node("SamplePlayer2D").play("hitWall")
  265.                     #find out which wall so the dust plays correctly
  266.                     #top wall
  267.                     if ball.get_pos().y < 20:  
  268.                         globals.whichWallWasHit = "top"
  269.                         emit_signal("hitWall", "top")
  270.                     if ball.get_pos().x < 20:  
  271.                         globals.whichWallWasHit = "left"
  272.                         emit_signal("hitWall", "left")
  273.                     if ball.get_pos().x > 280:  
  274.                         globals.whichWallWasHit = "right"
  275.                         emit_signal("hitWall", "right")
  276.                     #make some dust!
  277.                     ball.makeDust()
  278.                    
  279.                    
  280.                    
  281.            
  282.                    
  283.                 #did we hit another ball?
  284.                 elif entity.is_in_group("balls"):
  285.                     # Apply bounce physics, simply use normal.reflect x the bounce strength variable
  286.                     ball._movement = normal.reflect(ball._movement) * ball.bounce
  287.                     #play the wall hit sound
  288.                     ball.get_parent().get_node("SamplePlayer2D").play("hitBall")
  289.                
  290.                 elif entity.get_name() == "bat":
  291.                     # Apply bounce physics, simply use normal.reflect x the bounce strength variable
  292.                     ball._movement = normal.reflect(ball._movement) * ball.bounce*1.2  # add 20% as the gravity requires a bit more power to keep the ball playing well
  293.    
  294.  
  295.         #check if we're on screen or not
  296.         if !ball.get_node("VisibilityNotifier2D").is_on_screen():
  297.             #play a ball leaving sound
  298.             ball.get_parent().get_node("SamplePlayer2D").play("ballOut")   
  299.             ball.queue_free()          
  300.             #now check if we need to remove a life of not (there may be many balls on screen after all)
  301.             var ballsRemaining = ball.get_tree().get_nodes_in_group("balls").size()
  302.             if ballsRemaining <= 1:
  303.                 globals.lives -= 1
  304.                 #now refresh the visual indicators
  305.                 ball.get_parent().drawLifeIndicators()
  306.                 #if we still have at least one life left, place a new ball on the bat
  307.                 if globals.lives >=1:
  308.                     ball.get_node("/root/gameLevel").prepareBall()
  309.                 #otherwise it's game over... let's display the finish stuff
  310.                 else:
  311.                     #disable ball
  312.                     ball.set_state(STATE_LEVELOVER)
  313.                     #show the game over scene
  314.                     ball.get_tree().change_scene("gameOver.tscn")
  315.                    
  316.         # Move
  317.         ball.move(ball._movement*ball.speedIncrement)
  318.    
  319.     #finds where the ball/s hits the bat and deflects off at the correct angle based on the collission location
  320.     func findCollisionAreaOnBat(bat, delta):
  321.         var newMovement = Vector2(0,0) #used below to determine which direction we'll be pushing the ball
  322.         #Where is the bat pos?
  323.         var batLocString = str("/root/gameLevel/",bat)
  324.         var batLoc = ball.get_node(batLocString).get_transform().get_origin()
  325.         #Where is the ball pos?
  326.         var ballLoc = ball.get_transform().get_origin()
  327.         #what is the bat width?
  328.         var batWidth = ball.get_node("/root/gameLevel/bat/Sprite").get_texture().get_width()
  329.         #work out where the ball has hit the bat by subtracting the location of each (bat and ball) origins
  330.         #hitLocation will have a negative or positive number, based on how many pixels from bat centre we are
  331.         var hitLocation = ballLoc.x - batLoc.x 
  332.         #The line below turns the +- pixel count into a normalised value.  So it's between -1 and +1 at each extreme of the bat, depending on where it hits
  333.         #This gives me a specific number I can work with each time, regardless of bat size.  Nice!
  334.         var normalisedhitLocationX = (hitLocation/(batWidth/2));
  335.         #now multiply by the maximum bounce angle we want the ball to go off at when hitting edge of bat
  336.         var bounceAngle = normalisedhitLocationX * MAXBOUNCEANGLE;
  337.         #the new vector to pass to the move command
  338.         newMovement = Vector2(bounceAngle*2, globals.ballSpeed)    
  339.         #change the direction
  340.         ball._movement = newMovement
  341.  
  342.  
  343.     #it's good to be able to handle input from within the state... sometimes :-)
  344.     func input(event):
  345.         #once we have a click, touch or keypress, set ball in action, move out of this state, into moving state
  346.         if (event.type == InputEvent.MOUSE_BUTTON):
  347.             pass
  348.  
  349.     #so we know when it's the end of the state, and we can perform some actions before going to another state
  350.     func exit():
  351.         pass
  352.  
  353.  
  354.  
  355. #######################################################################################
  356. # class BatHugState -------------------------------------------------------------------
  357. #######################################################################################
  358. class BatHugState:
  359.     var ball
  360.    
  361.     #init gets called when an object of this class gets created
  362.     func _init(ball):
  363.         self.ball = ball
  364.         ball.get_node("AnimationPlayer").play("fadeIn")
  365.  
  366.     #frame by frame update
  367.     func update(delta):
  368.         var batPos = ball.get_tree().get_root().get_node("gameLevel/bat").get_pos()
  369.         #Move ball to bat centre, we're hugging the bat after all
  370.         ball.set_global_pos(Vector2(batPos.x,batPos.y-ball.ballDiameter))
  371.  
  372.     #it's good to be able to handle input from within the state... sometimes :-)
  373.     func input(event):
  374.         #once we have a click, touch or keypress, set ball in action, move out of this state, into moving state
  375.         if (event.type == InputEvent.MOUSE_BUTTON and event.button_index == BUTTON_LEFT and event.pressed):
  376.             ball.set_state(STATE_MOVING)
  377.  
  378.  
  379.     #so we know when it's the end of the state, and we can perform some actions before going to another state
  380.     func exit():
  381.         pass
  382.  
  383.        
  384. #######################################################################################
  385. # class BatMagnetState -------------------------------------------------------------------
  386. #######################################################################################
  387. class BatMagnetState:
  388.     var ball
  389.    
  390.     #init gets called when an object of this class gets created
  391.     func _init(ball):
  392.         self.ball = ball
  393.         ball.get_node("AnimationPlayer").play("fadeIn")
  394.  
  395.     #frame by frame update
  396.     func update(delta):
  397.         var batPos = ball.get_tree().get_root().get_node("gameLevel/bat").get_pos()
  398.         #Leave ball in the same X location that it hit the bat.  It's a magnet after all.
  399.         ######################################################################################
  400.         ######################################################################################
  401.         # This is where the proper offset should happen so magnet bat doesn't have the ball dead centre
  402.         # rather it should be where it hits the bat.  Must do this
  403.         ######################################################################################
  404.         ######################################################################################
  405. #       var ballOffset = ball.batOffset.x - batPos.x
  406. #       print("bat offset  = ", str(ball.batOffset.x))
  407. #       print("ball offset = ", str(ball.batOffset.x))
  408. #       #track the bat, so we're always "stuck" to it
  409.         ball.set_global_pos(Vector2(batPos.x,batPos.y-ball.ballDiameter))
  410.  
  411.     #it's good to be able to handle input from within the state... sometimes :-)
  412.     func input(event):
  413.         #once we have a click, touch or keypress, set ball in action, move out of this state, into moving state
  414.         if (event.type == InputEvent.MOUSE_BUTTON and event.button_index == BUTTON_LEFT and event.pressed):
  415.             ball.set_state(STATE_MOVING)
  416.  
  417.  
  418.     #so we know when it's the end of the state, and we can perform some actions before going to another state
  419.     func exit():
  420.         pass
  421.                
  422.        
  423.        
  424.        
  425.        
  426. #######################################################################################
  427. # class levelOverState - do nothing basically -----------------------------------------
  428. #######################################################################################
  429. class LevelOverState:
  430.     var ball
  431.    
  432.     #init gets called when an object of this class gets created
  433.     func _init(ball):
  434.         self.ball = ball
  435.         ball.get_node("AnimationPlayer").play("fadeOut")
  436.  
  437.     #frame by frame update
  438.     func update(delta):
  439.         pass
  440.  
  441.     #it's good to be able to handle input from within the state... sometimes :-)
  442.     func input(event):
  443.         pass
  444.  
  445.     #so we know when it's the end of the state, and we can perform some actions before going to another state
  446.     func exit():
  447.         pass
  448.        
  449.        
  450.        
  451. #######################################################################################
  452. # class multi Ball launch State
  453. # we want to start the ball near the existing ball and move it randomly
  454. # passing control then to the movestate so it can then behave like normal
  455. #######################################################################################
  456. class MultiLaunchState:
  457.     var ball
  458.        
  459.     #init gets called when an object of this class gets created
  460.     func _init(ball):
  461.         self.ball = ball
  462.         #choose a random launch angle
  463.         randomize()
  464.         var direction = range(-3,5)[randi()%range(-3,5).size()]
  465.         #send it skyward
  466.         launch(Vector2(direction,ball.initialBallSpeed)) #directional force
  467. #       print("I want to change to moving state from multi ball state now")
  468.         ball.set_state(STATE_MOVING)
  469.  
  470.     # Initialize shot from another script after adding it to the scene
  471.     func launch(directional_force):
  472.         ball._movement = directional_force
  473.         #play launch sound
  474.         ball.get_parent().get_node("SamplePlayer2D").play("launchBall02")
  475.  
  476.  
  477.     #frame by frame update
  478.     func update(delta):
  479.         ball.move(ball._movement*ball.speedIncrement)
  480.         ball.set_state(STATE_MOVING)
  481.    
  482.  
  483.     #it's good to be able to handle input from within the state... sometimes :-)
  484.     func input(event):
  485.         #once we have a click, touch or keypress, set ball in action, move out of this state, into moving state
  486.         if (event.type == InputEvent.MOUSE_BUTTON):
  487.             pass
  488.  
  489.     #so we know when it's the end of the state, and we can perform some actions before going to another state
  490.         pass
  491.     func exit():
  492.         pass
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement