Skip to content

Commit

Permalink
- Rewrote AI to determine where ball will land, and some other stuff …
Browse files Browse the repository at this point in the history
…based on angles
  • Loading branch information
austinhallock committed Mar 20, 2012
1 parent 0cad3e8 commit 020a699
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 14 deletions.
69 changes: 58 additions & 11 deletions src/client/scenes/slime_volleyball.coffee
Expand Up @@ -13,6 +13,14 @@ class SlimeVolleyball extends Scene
@buttons = { # create a back button
back: new Button(@width/2-Constants.BACK_BTN_WIDTH/2, Constants.SCOREBOARD_PADDING, Constants.BACK_BTN_WIDTH, Constants.BACK_BTN_HEIGHT, loader.getAsset('return'), loader.getAsset('return'), this)
}

# Set the difficulty
try
@percent = document.cookie.match(/AI_DIFFICULTY=(\d\.\d*)/i)[1]
catch e
@percent = Constants.AI_DIFFICULTY
finally
Constants.AI_DIFFICULTY = @percent # make sure it is set

@sprites = []
@sprites.push(@bg, @world.pole, @world.p1, @world.p2, @world.ball, @p1Scoreboard, @p2Scoreboard, @buttons.back)
Expand Down Expand Up @@ -59,16 +67,52 @@ class SlimeVolleyball extends Scene
changed

moveCPU: -> # implement a basic AI
if @ball.x > @pole.x && @ball.y < 200 && @ball.y > 150 && @p2.velocity.y == 0
@p2.velocity.y = -8
if @ball.x > @pole.x - @p1.width && @ball.x < @p2.x
@p2.x -= (Constants.MOVEMENT_SPEED*.75) + (Constants.MOVEMENT_SPEED*Constants.AI_DIFFICULTY)
if @ball.x > @pole.x - @p1.width && @ball.x + @ball.width + (@ball.velocity.x * Constants.AI_DIFFICULTY) > @p2.x + @p2.width && @ball.x + @ball.width < @width
@p2.x += (Constants.MOVEMENT_SPEED*.75) + (Constants.MOVEMENT_SPEED*Constants.AI_DIFFICULTY)
else if @ball.x > @pole.x - @p1.width && @ball.x + @ball.width + (@ball.velocity.x * Constants.AI_DIFFICULTY) > @p2.x + @p2.width && @ball.x + @ball.width >= @width
@p2.x -= (Constants.MOVEMENT_SPEED*.75) + (Constants.MOVEMENT_SPEED*Constants.AI_DIFFICULTY)
if @ball.x + @ball.radius > @p2.x + 30 && @ball.x + @ball.radius < @p2.x + 34
@p2.x += (Constants.MOVEMENT_SPEED*.75) + (Constants.MOVEMENT_SPEED*Constants.AI_DIFFICULTY)
return if @freezeGame
# Predict where the ball is going to end up
# Clone the ball obj
ball = {
x: @ball.x
y: @ball.y
velocity: {
x: @ball.velocity.x
y: @ball.velocity.y
}
acceleration: {
x: @ball.acceleration.x
y: @ball.acceleration.y
}
}
floor = @height - Constants.BOTTOM
while ball.y < floor - @p2.height # predicting the position where will be at slime height
# switch vel if hits wall
ball.velocity.x *= -1 if ball.x > @width || ball.x < 0
ball.x += ball.velocity.x * Constants.FPS_RATIO
ball.y += ball.velocity.y * Constants.FPS_RATIO
ball.velocity.y += ball.acceleration.y * Constants.FPS_RATIO

p2Pos = @p2.x + @p2.width / 2 - 14
pastP1 = @ball.x > @p1.x + @p1.width / 2 + @ball.radius
pastPole = ball.x > @pole.x
ballPos = @ball.x + @ball.radius
ballLand = ball.x + @ball.radius

# Angle between current pos, and land
ballAngle = Math.atan2( ballLand - ballPos, @ball.height )

# Where he wants to be to hit it (based on the angle of the ball and distance from pole)
# More weight is on the angle than the distance
# the randomness makes him stupider
sweetSpot = p2Pos - Constants.AI_DIFFICULTY * ( 1 - ( 1 / Constants.AI_DIFFICULTY ) * Math.random() ) * .8 * ( 2 * ( ( ( p2Pos - @pole.x ) / ( @width / 2 ) ) + 8 * ( 1.57 - Math.abs ballAngle ) ) )

# jump only if angle is steep enough, or ball will land past
if ( Math.abs( ballPos - sweetSpot ) <= 5 || ballPos - sweetSpot > 5 ) && @ball.y < 200 && @ball.y > 100 && @p2.velocity.y == 0 && ( ( ballAngle > -.8 && ballAngle < 0.8 ) )
@p2.velocity.y = -8 # jump
# ball will pass p2
if ballLand > sweetSpot + 5 # have him shoot at a lower angle if it's less steep
@p2.x += (Constants.MOVEMENT_SPEED*.55) + (Constants.MOVEMENT_SPEED*Constants.AI_DIFFICULTY)
# Ball past 1 and will land past net OR ball heading toward p1 from our side
else if ( ( pastP1 && pastPole ) || ( @ball.velocity.x < 0 && @ball.x > @pole.x ) ) && ballLand < sweetSpot - 5
@p2.x -= (Constants.MOVEMENT_SPEED*.55) + (Constants.MOVEMENT_SPEED*Constants.AI_DIFFICULTY)

draw: ->
# draw everything!
Expand Down Expand Up @@ -118,6 +162,7 @@ class SlimeVolleyball extends Scene
setTimeout(( => # start game in 1 second
@world.reset(winner)
@displayMsg = null
@stepLen = Constants.TICK_DURATION
@freezeGame = false
), 1000)

Expand All @@ -126,8 +171,10 @@ class SlimeVolleyball extends Scene
step: (timestamp) ->
this.next() # constantly demand ~60fps
return this.draw() if @freezeGame # don't change anything!

# apply input and then step
@world.step() # step physics
@world.step( @stepLen ) # step physics
@stepLen = null
# end game when ball hits ground
if @world.ball.y + @world.ball.height >= @world.height-Constants.BOTTOM
winner = if @world.ball.x+@world.ball.radius > @width/2 then @world.p1 else @world.p2
Expand Down
2 changes: 1 addition & 1 deletion src/shared/constants.coffee
Expand Up @@ -26,7 +26,7 @@ Constants =
MOVEMENT_SPEED: 4
JUMP_SPEED: 12
SLIME_START_HEIGHT: 91
AI_DIFFICULTY: 0.25
AI_DIFFICULTY: 0.35
MSG_FONT: 'Courier, monospace, sans-serif'
FPS_RATIO: 24 / 16 # in relation to what the initial speeds were set for (16ms)
TICK_DURATION: 24 #ms
Expand Down
5 changes: 3 additions & 2 deletions src/shared/world.coffee
Expand Up @@ -76,13 +76,14 @@ class World
@lastStep = now unless dontIncrementClock

# automatically break up longer steps into a series of shorter steps
if interval >= 1.3 * tick
if interval >= 1.3 * tick && @deterministic
while interval > 0
newInterval = if interval >= 1.3 * tick then tick else interval
this.step(newInterval, dontIncrementClock)
interval -= newInterval
return # don't continue stepping
else interval = tick
else if @deterministic
interval = tick

@numFrames = interval / tick

Expand Down

0 comments on commit 020a699

Please sign in to comment.