想敲代码又怕女朋友找?那就让她去玩桌面图标贪吃蛇,再也不用担心打扰自己敲代码了
想敲代码又怕女朋友找?那就让她去玩桌面图标贪吃蛇,再也不用担心打扰自己敲代码了
最近在逛博客的时候看见了一个有趣的项目,使用桌面图标进行贪吃蛇游戏。采用的代码是vb,但我实在不会vb,就找了C++中关于桌面图标获取句柄的文章进行查看(第一次接触这个,实属菜鸟)。效果还行 一步步获取到了想要的东西,然后偶然性看见了一位python大佬的博客,这就很OK了,看python代码就没啥问题了,然后就复制复制复制,看了一遍他的代码,接着就是来一个golang版的了。
在这里附上这位python版大佬的文章地址:用Windows10桌面图标玩python贪吃蛇
程序简单,思路算明确,至少我一遍就看懂了整个流程。然后就来一个golang吧。
一、定义一个航线结构体
type Vector struct {
x int32
y int32
}
func (vector *Vector) Add(vec Vector) Vector {
return Vector{vector.x + vec.x, vector.y + vec.y}
}
func (vector *Vector) Set(vec Vector) {
vector.x = vec.x
vector.y = vec.y
}
func (vector *Vector) Mult(num int32) Vector {
return Vector{vector.x * num, vector.y * num}
}
这里就不累赘了,简单的来说就是一个步伐坐标点。
二、获取窗体句柄、窗体大小以及图标数
这里使用了 “github.com/lxn/win” 包。下载吧,直接go get
至于这里如何获取桌面的句柄吧,给为可参考spy++如何使用的。
从spy++中可以看见,要获取viewlist窗口的句柄,只需要从"Program Manager"获取两级子窗口即可。
var hwnd win.HWND
hwnd = win.FindWindow(nil, syscall.StringToUTF16Ptr("Program Manager"))
hwnd = win.GetWindow(hwnd, win.GW_CHILD)
hwnd = win.GetWindow(hwnd, win.GW_CHILD)
var rect win.RECT
win.GetWindowRect(hwnd, &rect)
count := win.SendMessage(hwnd, win.LVM_GETITEMCOUNT, 0, 0)
代码如上,其中LVM_GETITEMCOUNT对于这个常量在,lxn/win这个包中并没有,所有我们就手动给他加一个即可。listview.go文件。
LVM_GETITEMCOUNT = LVM_FIRST + 4
三、给每一个图标进行位置重定位
pos = make([]Vector, count)
pos[0] = Vector{rect.Right / 2, rect.Bottom / 2}
pos[1] = Vector{rect.Right / 2, rect.Bottom / 2}
pos[2] = Vector{rand.Int31n(rect.Right-400) + 200, rand.Int31n(rect.Bottom-400) + 200}
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, 0, MAKELPARAM(pos[0].x, pos[0].y))
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, 1, MAKELPARAM(pos[1].x, pos[1].y))
lcur := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&cur))))
fmt.Println(lcur)
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, lcur, MAKELPARAM(pos[cur].x, pos[cur].y))
var i int
countInt = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&count))))
for i = cur + 1; i < countInt; i++ {
pos[i] = Vector{0, -100}
lp := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&i))))
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, lp, MAKELPARAM(pos[i].x, pos[i].y))
}
代码如上,其中LVM_SETITEMPOSITION对于这个常量在,lxn/win这个包中并没有,所有我们就手动给他加一个即可。listview.go文件。
LVM_SETITEMPOSITION = LVM_FIRST + 15
四、实现一个键盘监听
这个简单,直接上代码了:
func getKey() {
for {
if windev.KeyDownUp(windev.VK_LEFT) == 1 {
key = 37
}
if windev.KeyDownUp(windev.VK_UP) == 1 {
key = 38
}
if windev.KeyDownUp(windev.VK_RIGHT) == 1 {
key = 39
}
if windev.KeyDownUp(windev.VK_DOWN) == 1 {
key = 40
}
}
}
五、实现一个贪吃蛇了
首先是当蛇头位置改变时,后面的蛇身也需要跟着变化,那么剧需要对每一个位置重新赋值。
func run(pv Vector) {
for i := cur - 1; i > 0; i-- {
pos[i].Set(pos[i-1])
}
pos[0] = pos[0].Add(pv.Mult(60))
for i := 0; i < countInt; i++ {
lp := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&i))))
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, lp, MAKELPARAM(pos[i].x, pos[i].y))
}
time.Sleep(time.Millisecond * 200)
}
func MAKELPARAM(x, y int32) uintptr {
xt := int(x)
yt := int(y)
tem := yt << 16
a := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&tem))))
b := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&xt))))
return *a | *b
}
然后将键盘控制结合:
for {
// var v Vector
v := Vector{0, 0}
if key == 37 {
v = Vector{-1, 0}
}
if key == 38 {
v = Vector{0, -1}
}
if key == 39 {
v = Vector{1, 0}
}
if key == 40 {
v = Vector{0, 1}
}
run(v)
f1, _ := strconv.ParseFloat(fmt.Sprintf("%d", pos[0].x-pos[cur].x), 64)
f2, _ := strconv.ParseFloat(fmt.Sprintf("%d", pos[0].y-pos[cur].y), 64)
// fmt.Println(math.Sqrt(math.Pow(f1, 2) + math.Pow(f2, 2)))
if math.Sqrt(math.Pow(f1, 2)+math.Pow(f2, 2)) < 60 {
fmt.Println("jinru")
cur++
pos[cur].Set(Vector{rand.Int31n(rect.Right-400) + 200, rand.Int31n(rect.Bottom-400) + 200})
lp := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&cur))))
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, lp, MAKELPARAM(pos[cur].x, pos[cur].y))
}
fmt.Printf("当前蛇头地址坐标:%d,%d\n", pos[0].x, pos[0].y)
fmt.Printf("当前食物地址坐标:%d,%d\n", pos[cur].x, pos[cur].y)
}
六、全部实现代码
package main
import (
"fmt"
"math"
"math/rand"
"strconv"
"syscall"
"time"
"unsafe"
"github.com/cppdebug/windev"
"github.com/lxn/win"
)
type Vector struct {
x int32
y int32
}
func (vector *Vector) Add(vec Vector) Vector {
return Vector{vector.x + vec.x, vector.y + vec.y}
}
func (vector *Vector) Set(vec Vector) {
vector.x = vec.x
vector.y = vec.y
}
func (vector *Vector) Mult(num int32) Vector {
return Vector{vector.x * num, vector.y * num}
}
var cur = 2
var key int
func getKey() {
for {
if windev.KeyDownUp(windev.VK_LEFT) == 1 {
key = 37
}
if windev.KeyDownUp(windev.VK_UP) == 1 {
key = 38
}
if windev.KeyDownUp(windev.VK_RIGHT) == 1 {
key = 39
}
if windev.KeyDownUp(windev.VK_DOWN) == 1 {
key = 40
}
}
}
var pos []Vector
var countInt int
var hwnd win.HWND
func main() {
rand.Seed(time.Now().UnixNano())
hwnd = win.FindWindow(nil, syscall.StringToUTF16Ptr("Program Manager"))
hwnd = win.GetWindow(hwnd, win.GW_CHILD)
hwnd = win.GetWindow(hwnd, win.GW_CHILD)
var rect win.RECT
win.GetWindowRect(hwnd, &rect)
count := win.SendMessage(hwnd, win.LVM_GETITEMCOUNT, 0, 0)
fmt.Println(count)
pos = make([]Vector, count)
pos[0] = Vector{rect.Right / 2, rect.Bottom / 2}
pos[1] = Vector{rect.Right / 2, rect.Bottom / 2}
pos[2] = Vector{rand.Int31n(rect.Right-400) + 200, rand.Int31n(rect.Bottom-400) + 200}
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, 0, MAKELPARAM(pos[0].x, pos[0].y))
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, 1, MAKELPARAM(pos[1].x, pos[1].y))
lcur := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&cur))))
fmt.Println(lcur)
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, lcur, MAKELPARAM(pos[cur].x, pos[cur].y))
var i int
countInt = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&count))))
for i = cur + 1; i < countInt; i++ {
pos[i] = Vector{0, -100}
lp := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&i))))
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, lp, MAKELPARAM(pos[i].x, pos[i].y))
}
go getKey()
print(key)
for {
// var v Vector
v := Vector{0, 0}
if key == 37 {
v = Vector{-1, 0}
}
if key == 38 {
v = Vector{0, -1}
}
if key == 39 {
v = Vector{1, 0}
}
if key == 40 {
v = Vector{0, 1}
}
run(v)
f1, _ := strconv.ParseFloat(fmt.Sprintf("%d", pos[0].x-pos[cur].x), 64)
f2, _ := strconv.ParseFloat(fmt.Sprintf("%d", pos[0].y-pos[cur].y), 64)
// fmt.Println(math.Sqrt(math.Pow(f1, 2) + math.Pow(f2, 2)))
if math.Sqrt(math.Pow(f1, 2)+math.Pow(f2, 2)) < 60 {
fmt.Println("jinru")
cur++
pos[cur].Set(Vector{rand.Int31n(rect.Right-400) + 200, rand.Int31n(rect.Bottom-400) + 200})
lp := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&cur))))
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, lp, MAKELPARAM(pos[cur].x, pos[cur].y))
}
fmt.Printf("当前蛇头地址坐标:%d,%d\n", pos[0].x, pos[0].y)
fmt.Printf("当前食物地址坐标:%d,%d\n", pos[cur].x, pos[cur].y)
}
}
func run(pv Vector) {
for i := cur - 1; i > 0; i-- {
pos[i].Set(pos[i-1])
}
pos[0] = pos[0].Add(pv.Mult(60))
for i := 0; i < countInt; i++ {
lp := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&i))))
win.SendMessage(hwnd, win.LVM_SETITEMPOSITION, lp, MAKELPARAM(pos[i].x, pos[i].y))
}
time.Sleep(time.Millisecond * 200)
}
func MAKELPARAM(x, y int32) uintptr {
xt := int(x)
yt := int(y)
tem := yt << 16
a := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&tem))))
b := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&xt))))
return *a | *b
}
最后执行的时候别忘了,把这个取消了。点个赞收藏一波哦
如有需要改程序.exe执行文件的,可点击免费下载:桌面贪吃蛇go版.exe
本文地址:https://blog.csdn.net/qq_36269019/article/details/107858462
上一篇: 阿拉德之怒手游出金加防封的一点小心得