想敲代码又怕女朋友找?那就让她去玩桌面图标贪吃蛇,再也不用担心打扰自己敲代码了

想敲代码又怕女朋友找?那就让她去玩桌面图标贪吃蛇,再也不用担心打扰自己敲代码了

最近在逛博客的时候看见了一个有趣的项目,使用桌面图标进行贪吃蛇游戏。采用的代码是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文件。

扫描二维码关注公众号,回复: 11540743 查看本文章
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

猜你喜欢

转载自blog.csdn.net/qq_36269019/article/details/107858462