| |||
gi::createBinding -event "Up" -command {change_direction "Up"}
gi::createBinding -event "Down" -command {change_direction "Down"}
gi::createBinding -event "Left" -command {change_direction "Left"}
gi::createBinding -event "Right" -command {change_direction "Right"}
# 游戏常量
set cell_size 20 ;# 每个网格单元的大小
set width 30 ;# 网格宽度(单元格数)
set height 20 ;# 网格高度(单元格数)
set speed 100 ;# 游戏速度(毫秒)
# 游戏变量
set direction "Right" ;# 初始移动方向
set snake [list [list 5 10] [list 4 10] [list 3 10]] ;# 初始蛇身
set food {} ;# 食物位置
set game_over 0 ;# 游戏结束标志
set score 0 ;# 得分
# 生成随机食物位置
proc generate_food {} {
global width height snake food
while {1} {
set x [expr {int(rand() * $width)}]
set y [expr {int(rand() * $height)}]
set found 0
# 检查是否与蛇身重叠
foreach segment $snake {
lassign $segment sx sy
if {$x == $sx && $y == $sy} {
set found 1
break
}
}
if {!$found} {
set food [list $x $y]
return
}
}
}
# 绘制游戏元素
proc draw_game {} {
global cell_size snake food game_over height width
# .c delete all
db::destroy [db::getShapes -of [ed]]
for {set x 0} {$x <= $width} {incr x} {
# .c create line [expr {$x * $cell_size}] 0 \
# [expr {$x * $cell_size}] [expr {$height * $cell_size}] \
# -fill $grid_color -tags grid
le::createPath [list [list [expr {$x * $cell_size}] 0] \
[list [expr {$x * $cell_size}] [expr {$height * $cell_size}]]] -design [ed] -width 0.2 -lpp {M2 drawing}
}
# 绘制水平线
for {set y 0} {$y <= $height} {incr y} {
# .c create line 0 [expr {$y * $cell_size}] \
# [expr {$width * $cell_size}] [expr {$y * $cell_size}] \
# -fill $grid_color -tags grid
le::createPath [list [list 0 [expr {$y * $cell_size}]] \
[list [expr {$width * $cell_size}] [expr {$y * $cell_size}]]] -design [ed] -width 0.2 -lpp {M2 drawing}
}
# 绘制蛇身
foreach segment $snake {
lassign $segment x y
# .c create rectangle \
# [expr {$x * $cell_size}] \
# [expr {$y * $cell_size}] \
# [expr {($x+1) * $cell_size}] \
# [expr {($y+1) * $cell_size}] \
# -fill green -outline darkgreen
le::createRectangle [list [list [expr {$x * $cell_size}] \
[expr {$y * $cell_size}]] \
[list [expr {($x+1) * $cell_size}] \
[expr {($y+1) * $cell_size}]]] -design [ed] -lpp {CO drawing}
}
# 绘制蛇头(不同颜色)
if {[llength $snake] > 0} {
lassign [lindex $snake 0] hx hy
# .c create oval \
# [expr {$hx * $cell_size}] \
# [expr {$hy * $cell_size}] \
# [expr {($hx+1) * $cell_size}] \
# [expr {($hy+1) * $cell_size}] \
# -fill red -outline darkred
le::createEllipse [list [list [expr {$hx * $cell_size}] \
[expr {$hy * $cell_size}]] \
[list [expr {($hx+1) * $cell_size}] \
[expr {($hy+1) * $cell_size}]]] -design [ed] -lpp {M8 drawing}
}
# 绘制食物
if {[llength $food] == 2} {
lassign $food fx fy
# .c create oval \
# [expr {$fx * $cell_size}] \
# [expr {$fy * $cell_size}] \
# [expr {($fx+1) * $cell_size}] \
# [expr {($fy+1) * $cell_size}] \
# -fill yellow -outline gold
le::createEllipse [list [list [expr {$fx * $cell_size}] \
[expr {$fy * $cell_size}]] \
[list [expr {($fx+1) * $cell_size}] \
[expr {($fy+1) * $cell_size}]]] -design [ed] -lpp {OD drawing}
}
# 游戏结束显示
if {$game_over} {
puts "Game Over\n"
}
}
# 更新游戏状态
proc update_game {} {
global direction snake food game_over score speed width height
if {$game_over} return
# 获取蛇头位置
lassign [lindex $snake 0] head_x head_y
# 根据方向计算新蛇头位置
switch $direction {
"Up" {set new_head [list $head_x [expr {$head_y + 1}]]}
"Down" {set new_head [list $head_x [expr {$head_y - 1}]]}
"Left" {set new_head [list [expr {$head_x - 1}] $head_y]}
"Right" {set new_head [list [expr {$head_x + 1}] $head_y]}
}
# 检查碰撞
set collision 0
lassign $new_head nx ny
# 边界检查
if {$nx < 0 || $nx >= $width || $ny < 0 || $ny >= $height} {
set collision 1
}
# 自碰检查
foreach segment $snake {
lassign $segment sx sy
if {$nx == $sx && $ny == $sy} {
set collision 1
break
}
}
# 处理碰撞
if {$collision} {
set game_over 1
draw_game
return
}
# 添加新蛇头
set snake [linsert $snake 0 $new_head]
# 检查是否吃到食物
lassign $food fx fy
if {$nx == $fx && $ny == $fy} {
# 增加分数
incr score
# 生成新食物
generate_food
# 适当加速
if {$speed > 50} {
set speed [expr {$speed - 2}]
}
} else {
# 没吃到食物则移除蛇尾
set snake [lrange $snake 0 end-1]
}
# 重绘游戏
draw_game
# 继续游戏循环
after $speed update_game
}
# 键盘控制
proc change_direction {new_dir} {
global direction game_over
# 防止180度转向
switch $direction {
"Up" {if {$new_dir ne "Down"} {set direction $new_dir}}
"Down" {if {$new_dir ne "Up"} {set direction $new_dir}}
"Left" {if {$new_dir ne "Right"} {set direction $new_dir}}
"Right" {if {$new_dir ne "Left"} {set direction $new_dir}}
}
# 重新开始游戏
if {$game_over && [string tolower $new_dir] eq "r"} {
reset_game
}
}
# 重置游戏
proc reset_game {} {
global snake direction food game_over score
set snake [list [list 5 10] [list 4 10] [list 3 10]]
set direction "Right"
set game_over 0
set score 0
generate_food
draw_game
update_game
}
# 初始化游戏
generate_food
draw_game
update_game