NaaLaa

Full Version: improve cpu movement in pong
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I have programmed the movement in a very simple way for the player cpu following the ball, I would like some tips to improve the movement and make it seem more intelligent, and make it more fun to play.

I share all the code, the movement is in the player_cpu.move method of player_cpu:

Code:
'pong
include "player.n7"
include "player-cpu.n7"
include "ball.n7"

set window "example pong",640,480,false
set redraw off


'objeto-----------------------------------
player = Player()
ball = Ball()
player_cpu = Player_Cpu()


while not keydown(KEY_ESCAPE,true)
    set color 0,0,0
    cls
   
    'objetos-----------------------------
    player.update()
    player.Draw()
    player_cpu.update(ball)
    player_cpu.Draw()
    ball.update(player,player_cpu)
    ball.Draw()
    'lineas para el fondo------------------
    'draw rect 320,32,2,60,true
    'draw rect 320,120,2,60,true
    'draw rect 320,210,2,60,true
    'draw rect 320,300,2,60,true
    'draw rect 320,390,2,60,true
    'draw line 320,32,320,460
    'draw line 330,32,330,460
     
           
    redraw
    fwait 60
wend

Code:
'player

function Player()
    player = []
    player.Width = 20
    player.Height = 100
    player.x = 32 - player.Width/2
    player.y = 240 - player.Height/2
    player.speed = 5
    player.live = true
   
    player.update = function()
        if this.live = true
            this.move()
        endif
    endfunc
   
    player.Draw = function()
        if this.live = true
            set color 255,0,205
            draw rect this.x,this.y,this.Width,this.Height,true
        endif
    endfunc
   
    player.move = function()
        if keydown(KEY_UP,false) and this.y > 16
            this.y = this.y - this.speed
        elseif keydown(KEY_DOWN,false) and this.y < 370
            this.y = this.y + this.speed
        endif
    endfunc
   
    return player
endfunc


Code:
'player-cpu

function Player_Cpu()
    player_cpu = []
    player_cpu.Width = 20
    player_cpu.Height = 100
    player_cpu.x = 608 - player_cpu.Width/2
    player_cpu.y = 240 - player_cpu.Height/2
    player_cpu.speed = 5
    player_cpu.live = true
    'player_cpu.ball = ball

    player_cpu.update = function(ball)
        if this.live
            this.move(ball)
        endif
    endfunc

    player_cpu.Draw = function()
        if this.live
            set color 255,204,0
            draw rect this.x,this.y,this.Width,this.Height,true
        endif
    endfunc
   
    player_cpu.move = function(ball)
        if this.y > ball.y and this.y > 16
            this.y = this.y - this.speed
        endif
       
        if this.y < ball.y and this.y < 370
            this.y = this.y + this.speed
        endif
    endfunc

    return player_cpu
endfunc

Code:
'ball
include "miscellaneous.n7"

function Ball()
    ball = []
    ball.Width = 16
    ball.Height = 16
    ball.x = 320 - ball.Width / 2
    ball.y = 240 - ball.Height / 2
    ball.speedX = 2
    ball.speedY = 2
    ball.live = true
    'ball.player = player

    ball.update = function(player,player_cpu)
        if this.live = true
            this.move()
            this.bounce()
            this.collision_player(player)
            this.collision_player_cpu(player_cpu)
        endif
    endfunc

    ball.Draw = function()
        if this.live = true
            set  color 200,200,200
            draw rect this.x,this.y,this.Width,this.Height,true
            'draw ellipse this.x,this.y,9,9,true
        endif
    endfunc

    ball.move = function()
        this.x = this.x + this.speedX
        this.y = this.y + this.speedY
    endfunc

    ball.bounce = function()
        if this.x <= 0 or this.x >= 640
            this.speedX = this.speedX * -1
        endif
     
        if this.y <= 0 or this.y >= 480
            this.speedY = this.speedY * -1
        endif
    endfunc

    ball.collision_player = function(player)
        'colision con la x
        if collision_rect(this.x+this.speedX,this.y,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
            this.speedX = this.speedX * -1
        endif
        'colision con la y
        if collision_rect(this.x,this.y+this.speedY,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
            this.speedY = this.speedY * -1
        endif
    endfunc
   
    ball.collision_player_cpu = function(player_cpu)
        'colision con la x
        if collision_rect(this.x+this.speedX,this.y,this.Width,this.Height,player_cpu.x,player_cpu.y,player_cpu.Width,player_cpu.Height)
            this.speedX = this.speedX * -1
        endif
        'colision con la y
        if collision_rect(this.x,this.y+this.speedY,this.Width,this.Height,player_cpu.x,player_cpu.y,player_cpu.Width,player_cpu.Height)
            this.speedY = this.speedY * -1
        endif
    endfunc

    return ball
endfunc

Code:
'miscellaneous

'variables y funciones para manejar los puntos
visible score_player = 0
visible score_player_cpu = 0

function get_score_player()
    return score_player
endfunc

function get_score_player_cpu()
    return score_player_cpu
endfunc

'funcion de colision--------------------------------
function collision_rect(x1,y1,w1,h1,x2,y2,w2,h2)
    return x1 + w1 > x2 and x1 < x2 + w2 and
            y1 + h1 > y2 and y1 < y2 + h2
endfunc
In most cases, making a computer opponent seem human is about making it more stupid - make it do stupid little moves, make pauses etc Smile

Johnno posted a pong on the forum written in n7. I think it was based on something I wrote in n6. So I'll post the n6 source code here. I just tried it, and the computer really does make silly little moves and pauses - making it seem more human.

Code:
rem ==================================================================
rem Pong, from basicprogramming.org.
rem
rem By Marcus Johansson.
rem ==================================================================

import "Speed.lib"

set window 0, 0, 320, 240, false, 2
set redraw off

plyX = 8
comX = 320 - 24
comY# = 120.0
comWantedY# = 120.0
comTimer = 25
hasBall = 1
ballX#
ballY#
ballDX#
ballDY#
ballSpeed# = 3.0
comScore = 0
plyScore = 0

do
    plyY = mousey()

    if hasBall = 1
        ballX# = float(plyX + 16)
        ballY# = float(plyY - 4)
        if mousebutton(0)
            ballDX = 1.0
            ballDY = 0.0
            ballSpeed = 2.0
            hasBall = 0
        endif
    elseif hasBall = 2
        ballX = float(comX - 8)
        ballY = comY - 4.0
    else
        ballX = ballX + ballDX*ballSpeed
        ballY = ballY + ballDY*ballSpeed
        if ballY < 0.0
            ballY = 0.0
            ballDY = -ballDY
        elseif ballY# > 240.0 - 8.0
            ballY = 240.0 - 8.0
            ballDY = -ballDY
        endif
        
        
        if ballDX < 0.0
            if RectsOverlap(plyX, plyY - 24, 16, 48, int(ballX), int(ballY), 8, 8)
                dy# = (ballY - float(plyY))/64.0
                dx# = 0.5
                k# = 1.0/sqr(dx*dx + dy*dy)
                ballDX# = k*dx
                ballDY# = k*dy
                ballSpeed = min#(ballSpeed*1.1, 6.0)
            endif
        else
            if RectsOverlap(comX, int(comY) - 24, 16, 48, int(ballX), int(ballY), 8, 8)
                dy# = (ballY - comY)/64.0
                dx# = -0.5
                k# = 1.0/sqr(dx*dx + dy*dy)
                ballDX# = k*dx
                ballDY# = k*dy
                ballSpeed = min#(ballSpeed*1.1, 6.0)
            endif
        endif

        if ballX > 320.0
            hasBall = 1
            plyScore = plyScore + 1
        elseif ballX < -8.0
            hasBall = 2
            comTimer = 50
            comWantedY = float(rnd(240))
            comScore = comScore + 1
        endif
    endif

    comTimer = comTimer - 1
    if comTimer <= 0
        if hasBall = 1
            comWantedY = ballY - 16.0 + float(rnd(32)) + (float(comX) - ballX)/ballSpeed*ballDY
            comTimer = comTimer + 25 + rnd(25)
        elseif hasBall = 2
            hasBall = 0
            ballDX = -1.0
            ballDY = 0.0
            ballSpeed = 2.0
        else
            comWantedY = ballY - 20.0 + float(rnd(40)) + (float(comX) - ballX)/ballSpeed*ballDY
            if ballDX < 0.0
                comTimer = comTimer + 20 + rnd(20)
            else
                comTimer = comTimer + 6 + rnd(6)
            endif
        endif
    endif
    comY = 0.90*comY + 0.1*comWantedY

    set color 0, 0, 0
    cls
    set color 255, 255, 255
    for y = 0 to 29
        draw rect 160 - 2, y*8 + 2, 4, 4, true
    next

    draw rect plyX, plyY - 24, 16, 48, true
    draw rect comX, int(comY) - 24, 16, 48, true
    draw rect int(ballX), int(ballY), 8, 8, true
    set caret 16, 8
    center plyScore
    set caret 320 - 16, 8
    center comScore

    redraw
    proc SPD_HoldFrame(60)    
until keydown(27) or not running()

function RectsOverlap(x0, y0, w0, h0, x1, y1, w1, h1)
    if x0 + w0 < x1 then return false
    if y0 + h0 < y1 then return false
    if x1 + w1 < x0 then return false
    if y1 + h1 < y0 then return false
    return true
endfunc
Certainly is a "golden oldie"... Gotta love the classics...
It seems that if I increase the speed of the cpu player, instead of moving faster, it becomes more clumsy, some way to make it move faster and make it more difficult to place the ball on it.