- UID
- 205569
- 在线时间
- 0 小时
- 最后登录
- 2015-6-3
- 注册时间
- 2012-8-25
- 宅魂
- 2820 点
- 贡献
- 299 点
- 宅币
- 17268 枚
- 灵石
- 0 块
- 元气(技能点)
- 34 点
- 活跃
- 0 ℃
- 听众
- 9
- 收听
- 1
该用户从未签到
技术宅认证程序员
重度中二患者
- 积分
- 28325
|
本帖最后由 foodszhu 于 2013-4-2 01:03 编辑
无聊啊无聊啊 、
前面两篇:
配置篇
Hello World篇
-----------------------------------------------------------------------------------------------------------------------
这次我们真正尝试一个稍微像游戏的东西--井字游戏。。。就是那种在 3 X 3方格中画O和X,如果三个连成一线就是胜利。。虽然这东西已经证明先手必胜(不败),但是作为最基础的游戏。就来稍微做一下吧
首先准备一个3 X 3的网格。。。大小为600 X 600
好吧。。。。我不会用GIMP。。。。。自己手画就这么丑。。。。求不喷死。。。
再准备一下O和X的图片。。。这次我们把他们放到一起,一个200 X 400 的图片
(如果能自己画的话还是自己画吧。。。我这个太丑了。。泪奔)
这次我们将尝试事件驱动的编程
[mw_shl_code=applescript,true]package main
import (
"github.com/banthar/Go-SDL/sdl"
)
func main() {
var back_ground, ox, screen *sdl.Surface[/mw_shl_code]
包名,引入包名,主函数,界面surface声明
[mw_shl_code=applescript,true] logic_plane := [3][3]int{}
running := true
turn := true[/mw_shl_code]
逻辑板的声明。。一个3X3的数组。。。
Go语言中数组定义方方式 "[n]<type>" 有点古怪。长度下标 n 必须是编译期正整数常量 (或常量表达式)。 长
度是类型的组成部分,也就是说 "[10]int" 和 "[20]int" 是完全不同的两种数组类型。数组是值类型,也就是说会拷⻉贝整个数组内存进行行值传递。可用用 slice 或指针代替。(跟C不同哦)
可以用用 new() 创建数组,返回数组指针。var a = new([10]int)
[mw_shl_code=applescript,true] sdl.Init(sdl.INIT_EVERYTHING)
defer sdl.Quit()
screen = sdl.SetVideoMode(600, 600, 32, sdl.SWSURFACE)
back_ground = sdl.Load("back_ground.png")
ox = sdl.Load("ox.png")
defer back_ground.Free()
defer ox.Free()
sdl.WM_SetCaption("井字游戏", "")[/mw_shl_code]
依旧是老套的初始化与图片的读取,释放。窗口标题的设置。。
下面进入核心事件循环
在SDL中,每当有一个事件发生, 它会被置于事件队列中。事件队列为每个发生的事件保存了事件数据。
所以如果你按一下鼠标按钮,再移动一下鼠标,接着再按下键盘上某个按键,事件队列看起来会像这样:
我们将用一个循环反复捕捉事件。。并且读取事件来驱动整个程序的运作
首先,先说Go的循环
for 支持三种形式:
for init; condition; post {}
for condition {}
for {}
第一种就是C语言的for循环,初始化,判断条件,步进值
第二种就类似while循环,当condition = false时退出循环
第三种就是 while(1),无限循环,只能通过break来退出循环(goto也可,不推荐)
当然go还提供range保留字和for搭配产生迭代器的效果。(很类似python,不过没那么好用,而且基本都是提前算好,不是真正意义上的迭代器)
我们利用running变量判断程序是否进行
[mw_shl_code=applescript,true]for running {
event := sdl.PollEvent()
switch e := event.(type) {
//switch a.(type)检查接口a的类型,然后e就相当于转换了接口的类型
case *sdl.QuitEvent:
running = false
return[/mw_shl_code]
sdl.PollEvent函数左右是从消息队列里提取出一个事件,并返回。返回值是sdl.Event,sdl.Event是一个接口。。。
这里接口解释起来比较复杂。。。
所谓接口。。我们简单认为就是满足一定特性的一系列事物,对于Go,就是他一定拥有某些方法,对于一个接口,它实际存储的可能是任何类型,但都必须有某个方法。。这样便实现了多态。。这里因为还没说方法。。就先不多说接口问题,
switch语句用于多路选择,在各个语言中都有涉及,不过Go语言明显吸取了C的教训,switch中case语句可以跟任何类型的常量/变量,而且默认case语句后自带break,也就是不会从一个case语句跑到另一个中,如果真需要这样做,必须显式使用fallthrough来修饰。。。同样有default来进行默认情况的匹配
而我们这里,用一个switch比较特别的用法,swith a.(type)
a.(type)这种用法仅能在switch语句中使用,用来匹配a的类型 结果返回a的类型。
而这里我们由于event是一个接口,所以它返回的一定是它所存储的数据的类型,由于接口存储的必然是指针,所以我们就可以由此判断
sdl.QuitEvent是离开的事件,也就是窗口点x,右键退出等所响应的事件
我们将running = false。意味循环结束
[mw_shl_code=applescript,true] case *sdl.MouseButtonEvent:
if e.Type == sdl.MOUSEBUTTONDOWN {
switch e.Button {
case sdl.BUTTON_RIGHT:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
logic_plane[j] = 0
}
}
case sdl.BUTTON_LEFT:
i := e.X / 200
j := e.Y / 200
if logic_plane[j] == 0 {
if turn {
turn = !turn
logic_plane[j] = 1
} else {
turn = !turn
logic_plane[j] = 2
}
}
}
}
}[/mw_shl_code]
下面我们匹配鼠标事件,如果鼠标右键单击,则游戏重新开始,
左键单击,则在逻辑板中进行变化。每点一次turn切换一次,意味这两个人交替下子。
最后我们将一下精灵图的概念
当我们需要一系列较小图片来组成整个程序时,我们往往不希望每一个小图片都是一个独立的文件,这样无疑使得读取更加费时,操作更加复杂,所以提出了精灵图的概念,将一个子图集合放入一个单独的图片文件中,并blit你想要使用的部分。
[mw_shl_code=applescript,true] screen.Blit(nil, back_ground, nil)
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if logic_plane[j] == 1 {
screen.Blit(&sdl.Rect{int16(i*200 + 10), int16(j*200 + 10), 180, 180},
ox, &sdl.Rect{0, 0, 170, 170})
} else if logic_plane[j] == 2 {
screen.Blit(&sdl.Rect{int16(i*200 + 10), int16(j*200 + 10), 180, 180},
ox, &sdl.Rect{0, 200, 170, 170})
}
}
}
screen.Flip()
}
}[/mw_shl_code]
首先我们将背景贴到屏幕上。
我们知道方法Blit中,调用者是目标界面,第二个参数是源界面,那么第一个参数和第三个参数是干什么的呢?
这两个参数是接受一个sdl.Rect结构,第一个参数表示将要贴在目标界面的哪个部分,第三个参数表示取自源界面的哪个部分。这样就完成了精灵图的操作了。
每次只要根据图片选择一定矩形区域内的图片,就可以部分显示了。。
至于其实最后还应该写一下胜利逻辑。。。由于跟SDL就没什么关系了。。。所以也就懒得写了。。。。
效果图
全部源码:
[mw_shl_code=applescript,true]package main
import (
"github.com/banthar/Go-SDL/sdl"
)
func main() {
var back_ground, ox, screen *sdl.Surface
logic_plane := [3][3]int{}
running := true
turn := true
sdl.Init(sdl.INIT_EVERYTHING)
defer sdl.Quit()
screen = sdl.SetVideoMode(600, 600, 32, sdl.SWSURFACE)
back_ground = sdl.Load("back_ground.png")
ox = sdl.Load("ox.png")
defer back_ground.Free()
defer ox.Free()
sdl.WM_SetCaption("井字游戏", "")
for running {
event := sdl.PollEvent()
switch e := event.(type) {
//switch a.(type)检查接口a的类型,然后e就相当于转换了接口的类型
case *sdl.QuitEvent:
running = false
return
case *sdl.MouseButtonEvent:
if e.Type == sdl.MOUSEBUTTONDOWN {
switch e.Button {
case sdl.BUTTON_RIGHT:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
logic_plane[j] = 0
}
}
case sdl.BUTTON_LEFT:
i := e.X / 200
j := e.Y / 200
if logic_plane[j] == 0 {
if turn {
turn = !turn
logic_plane[j] = 1
} else {
turn = !turn
logic_plane[j] = 2
}
}
}
}
}
screen.Blit(nil, back_ground, nil)
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if logic_plane[j] == 1 {
screen.Blit(&sdl.Rect{int16(i*200 + 10), int16(j*200 + 10), 180, 180},
ox, &sdl.Rect{0, 0, 170, 170})
} else if logic_plane[j] == 2 {
screen.Blit(&sdl.Rect{int16(i*200 + 10), int16(j*200 + 10), 180, 180},
ox, &sdl.Rect{0, 200, 170, 170})
}
}
}
screen.Flip()
}
}
[/mw_shl_code]
————————————————————————————————————————————————————————————————————————
越写到后面越累啊。。。。最后就懒得说话了。。。。
下次应该就是打砖块了。。。。不过应该就分很多期写了。。。一起说起来太麻烦。。。
反应不好。。不爽求发糖@Whisper1166 @Mr_Alex
|
评分
-
参与人数 2 | 宅魂 +1 |
宅币 +31 |
贡献 +1 |
元气(技能点) +2 |
活跃 +1 |
收起
理由
|
cao884203
| + 1 |
+ 1 |
|
|
+ 1 |
Σ( ° △ °|||)︴ 碉堡了 |
Mr_Alex
| |
+ 30 |
+ 1 |
+ 2 |
|
Σ( ° △ °|||)︴ 碉堡了 |
查看全部评分
|