Go与SDL写小游戏(三)----井字游戏
本帖最后由 foodszhu 于 2013-4-2 01:03 编辑无聊啊无聊啊$38$、
前面两篇:
配置篇
Hello World篇
-----------------------------------------------------------------------------------------------------------------------
这次我们真正尝试一个稍微像游戏的东西--井字游戏。。。就是那种在 3 X 3方格中画O和X,如果三个连成一线就是胜利。。虽然这东西已经证明先手必胜(不败),但是作为最基础的游戏。就来稍微做一下吧
首先准备一个3 X 3的网格。。。大小为600 X 600
好吧。。。。我不会用GIMP。。。。。自己手画就这么丑。。。。求不喷死。。。
再准备一下O和X的图片。。。这次我们把他们放到一起,一个200 X 400 的图片
(如果能自己画的话还是自己画吧。。。我这个太丑了。。泪奔)
这次我们将尝试事件驱动的编程
package main
import (
"github.com/banthar/Go-SDL/sdl"
)
func main() {
var back_ground, ox, screen *sdl.Surface
包名,引入包名,主函数,界面surface声明
logic_plane := int{}
running := true
turn := true
逻辑板的声明。。一个3X3的数组。。。
Go语言中数组定义方方式 "<type>" 有点古怪。长度下标 n 必须是编译期正整数常量 (或常量表达式)。 长
度是类型的组成部分,也就是说 "int" 和 "int" 是完全不同的两种数组类型。数组是值类型,也就是说会拷⻉贝整个数组内存进行行值传递。可用用 slice 或指针代替。(跟C不同哦)
可以用用 new() 创建数组,返回数组指针。var a = new(int)
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("井字游戏", "")
依旧是老套的初始化与图片的读取,释放。窗口标题的设置。。
下面进入核心事件循环
在SDL中,每当有一个事件发生, 它会被置于事件队列中。事件队列为每个发生的事件保存了事件数据。
所以如果你按一下鼠标按钮,再移动一下鼠标,接着再按下键盘上某个按键,事件队列看起来会像这样:
http://tjumyk.github.com.sixxs.org/sdl-tutorial-cn/lessons/lesson04/queue.jpg
我们将用一个循环反复捕捉事件。。并且读取事件来驱动整个程序的运作
首先,先说Go的循环
for 支持三种形式:
for init; condition; post {}
for condition {}
for {}
第一种就是C语言的for循环,初始化,判断条件,步进值
第二种就类似while循环,当condition = false时退出循环
第三种就是 while(1),无限循环,只能通过break来退出循环(goto也可,不推荐)
当然go还提供range保留字和for搭配产生迭代器的效果。(很类似python,不过没那么好用,而且基本都是提前算好,不是真正意义上的迭代器)
我们利用running变量判断程序是否进行
for running {
event := sdl.PollEvent()
switch e := event.(type) {
//switch a.(type)检查接口a的类型,然后e就相当于转换了接口的类型
case *sdl.QuitEvent:
running = false
return
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。意味循环结束
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 = 0
}
}
case sdl.BUTTON_LEFT:
i := e.X / 200
j := e.Y / 200
if logic_plane == 0 {
if turn {
turn = !turn
logic_plane = 1
} else {
turn = !turn
logic_plane = 2
}
}
}
}
}
下面我们匹配鼠标事件,如果鼠标右键单击,则游戏重新开始,
左键单击,则在逻辑板中进行变化。每点一次turn切换一次,意味这两个人交替下子。
最后我们将一下精灵图的概念
当我们需要一系列较小图片来组成整个程序时,我们往往不希望每一个小图片都是一个独立的文件,这样无疑使得读取更加费时,操作更加复杂,所以提出了精灵图的概念,将一个子图集合放入一个单独的图片文件中,并blit你想要使用的部分。
screen.Blit(nil, back_ground, nil)
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if logic_plane == 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 == 2 {
screen.Blit(&sdl.Rect{int16(i*200 + 10), int16(j*200 + 10), 180, 180},
ox, &sdl.Rect{0, 200, 170, 170})
}
}
}
screen.Flip()
}
}
首先我们将背景贴到屏幕上。
我们知道方法Blit中,调用者是目标界面,第二个参数是源界面,那么第一个参数和第三个参数是干什么的呢?
这两个参数是接受一个sdl.Rect结构,第一个参数表示将要贴在目标界面的哪个部分,第三个参数表示取自源界面的哪个部分。这样就完成了精灵图的操作了。
每次只要根据图片选择一定矩形区域内的图片,就可以部分显示了。。
至于其实最后还应该写一下胜利逻辑。。。由于跟SDL就没什么关系了。。。所以也就懒得写了。。。。
效果图
全部源码:
package main
import (
"github.com/banthar/Go-SDL/sdl"
)
func main() {
var back_ground, ox, screen *sdl.Surface
logic_plane := 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 = 0
}
}
case sdl.BUTTON_LEFT:
i := e.X / 200
j := e.Y / 200
if logic_plane == 0 {
if turn {
turn = !turn
logic_plane = 1
} else {
turn = !turn
logic_plane = 2
}
}
}
}
}
screen.Blit(nil, back_ground, nil)
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if logic_plane == 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 == 2 {
screen.Blit(&sdl.Rect{int16(i*200 + 10), int16(j*200 + 10), 180, 180},
ox, &sdl.Rect{0, 200, 170, 170})
}
}
}
screen.Flip()
}
}
————————————————————————————————————————————————————————————————————————
越写到后面越累啊。。。。最后就懒得说话了。。。。
下次应该就是打砖块了。。。。不过应该就分很多期写了。。。一起说起来太麻烦。。。
反应不好。。不爽求发糖@Whisper1166 @Mr_Alex
_(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)_【看到大师后吓到尸横遍野】 晓晓酱 发表于 2013-4-2 02:24 static/image/common/back.gif
_(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)_【看到大师后吓到尸横遍野】 ...
只是写很简单的东西吧。。。。
我才是尸横遍野啊! 支持下go语言,虽然我还没用过:90: foodszhu 发表于 2013-4-2 12:04 static/image/common/back.gif
只是写很简单的东西吧。。。。
我才是尸横遍野啊!
可能是因为我太渣了_(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)__(:3」∠)_ 这个IDE是什么啊,看上去很不错啊 langyxxl 发表于 2013-4-2 16:41 static/image/common/back.gif
这个IDE是什么啊,看上去很不错啊
sublime text。。。。一款非常不错的文本编辑器。。。但不是IDE。。。不过配置配置可以达到IDE的效果的说
虽然说更喜欢vim,但是vim的配色实在比不上这个。。。
嗯 嗯晚上回去再看代码 moxiagy 发表于 2013-4-2 16:49 static/image/common/back.gif
嗯 嗯晚上回去再看代码
写的非常丑。。。。捂脸。。。求轻喷。。。$61$
页:
[1]