欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-18 10:09:31
golang实现桌面图标贪吃蛇最近在逛博客的时候看见了一个有趣的项目,使用桌面图标进行贪吃蛇游戏。采用的代码是vb,但我实在不会vb,就找了C++中关于桌面图标获取句柄的文章进行查看(第一次接触这个,实属菜鸟)。效果还行 一步步获取到了想要的东西,然后偶然性看见了一位python大佬的博客,这就很OK了,看python代码就没啥问题了,然后就复制复制复制,看了一遍他的代码,接着就是来一个golang版的了。在这里附上这位python版大佬的文章地址:用Windows10桌面图标玩python贪吃蛇程序...

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

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

相关标签: golang go windows